From ba1b1ae3806490cce16a9c8957b52cd74967f463 Mon Sep 17 00:00:00 2001 From: Jeff Hartmann Date: Tue, 4 Apr 2000 22:08:14 +0000 Subject: Merged mga branch with trunk --- libdrm/xf86drm.c | 142 ++++- linux-core/Makefile.kernel | 18 +- linux-core/drmP.h | 127 +++- linux-core/i810_dma.c | 1228 ++++++++++++++++++++--------------- linux-core/i810_drm.h | 93 +++ linux-core/i810_drv.c | 141 ++-- linux-core/i810_drv.h | 132 +++- linux-core/mga_drv.c | 34 +- linux-core/tdfx_drv.c | 44 +- linux/Makefile.kernel | 18 +- linux/Makefile.linux | 44 +- linux/agpsupport.c | 15 +- linux/bufs.c | 7 +- linux/ctxbitmap.c | 10 +- linux/dma.c | 21 +- linux/drm.h | 77 ++- linux/drmP.h | 127 +++- linux/gamma_drv.c | 4 + linux/i810_bufs.c | 376 ++++------- linux/i810_context.c | 205 ++++++ linux/i810_dma.c | 1228 ++++++++++++++++++++--------------- linux/i810_drm.h | 93 +++ linux/i810_drv.c | 141 ++-- linux/i810_drv.h | 132 +++- linux/memory.c | 151 ++++- linux/mga_bufs.c | 430 ++++++------- linux/mga_clear.c | 417 ------------ linux/mga_context.c | 60 +- linux/mga_dma.c | 1522 ++++++++++++++++++++++++-------------------- linux/mga_dma.h | 112 ---- linux/mga_drm.h | 261 ++++++++ linux/mga_drm_public.h | 218 ------- linux/mga_drv.c | 34 +- linux/mga_drv.h | 286 ++++++--- linux/mga_state.c | 782 +++++++++++++++++++---- linux/mga_state.h | 13 - linux/mgareg_flags.h | 930 --------------------------- linux/picker.c | 10 + linux/proc.c | 7 +- linux/tdfx_context.c | 18 +- linux/tdfx_drv.c | 44 +- linux/vm.c | 3 +- shared-core/drm.h | 77 ++- shared/drm.h | 77 ++- tests/drmstat.c | 2 +- 45 files changed, 5638 insertions(+), 4273 deletions(-) create mode 100644 linux-core/i810_drm.h create mode 100644 linux/i810_context.c create mode 100644 linux/i810_drm.h delete mode 100644 linux/mga_clear.c delete mode 100644 linux/mga_dma.h create mode 100644 linux/mga_drm.h delete mode 100644 linux/mga_drm_public.h delete mode 100644 linux/mga_state.h delete mode 100644 linux/mgareg_flags.h diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 3b0f98acd..8b97c7da9 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -418,7 +418,8 @@ int drmAddMap(int fd, return 0; } -int drmAddBufs(int fd, int count, int size, int flags) +int drmAddBufs(int fd, int count, int size, drmBufDescFlags flags, + int agp_offset) { drm_buf_desc_t request; @@ -427,6 +428,8 @@ int drmAddBufs(int fd, int count, int size, int flags) request.low_mark = 0; request.high_mark = 0; request.flags = flags; + request.agp_start = agp_offset; + if (ioctl(fd, DRM_IOCTL_ADD_BUFS, &request)) return -errno; return request.count; } @@ -744,6 +747,143 @@ int drmDestroyDrawable(int fd, drmDrawable handle) return 0; } +int drmAgpAcquire(int fd) +{ + if (ioctl(fd, DRM_IOCTL_AGP_ACQUIRE, NULL)) return -errno; + return 0; +} + +int drmAgpRelease(int fd) +{ + if (ioctl(fd, DRM_IOCTL_AGP_RELEASE, NULL)) return -errno; + return 0; +} + +int drmAgpEnable(int fd, unsigned long mode) +{ + drm_agp_mode_t m; + + m.mode = mode; + if (ioctl(fd, DRM_IOCTL_AGP_ENABLE, &m)) return -errno; + return 0; +} + +int drmAgpAlloc(int fd, unsigned long size, unsigned long type, + unsigned long *address, unsigned long *handle) +{ + drm_agp_buffer_t b; + *handle = 0; + b.size = size; + b.handle = 0; + b.type = type; + if (ioctl(fd, DRM_IOCTL_AGP_ALLOC, &b)) return -errno; + if (address != 0UL) *address = b.physical; + *handle = b.handle; + return 0; +} + +int drmAgpFree(int fd, unsigned long handle) +{ + drm_agp_buffer_t b; + + b.size = 0; + b.handle = handle; + if (ioctl(fd, DRM_IOCTL_AGP_FREE, &b)) return -errno; + return 0; +} + +int drmAgpBind(int fd, unsigned long handle, unsigned long offset) +{ + drm_agp_binding_t b; + + b.handle = handle; + b.offset = offset; + if (ioctl(fd, DRM_IOCTL_AGP_BIND, &b)) return -errno; + return 0; +} + +int drmAgpUnbind(int fd, unsigned long handle) +{ + drm_agp_binding_t b; + + b.handle = handle; + b.offset = 0; + if (ioctl(fd, DRM_IOCTL_AGP_UNBIND, &b)) return -errno; + return 0; +} + +int drmAgpVersionMajor(int fd) +{ + drm_agp_info_t i; + + if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return -errno; + return i.agp_version_major; +} + +int drmAgpVersionMinor(int fd) +{ + drm_agp_info_t i; + + if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return -errno; + return i.agp_version_minor; +} + +unsigned long drmAgpGetMode(int fd) +{ + drm_agp_info_t i; + + if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0; + return i.mode; +} + +unsigned long drmAgpBase(int fd) +{ + drm_agp_info_t i; + + if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0; + return i.aperture_base; +} + +unsigned long drmAgpSize(int fd) +{ + drm_agp_info_t i; + + if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0; + return i.aperture_size; +} + +unsigned long drmAgpMemoryUsed(int fd) +{ + drm_agp_info_t i; + + if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0; + return i.memory_used; +} + +unsigned long drmAgpMemoryAvail(int fd) +{ + drm_agp_info_t i; + + if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0; + return i.memory_allowed; +} + +unsigned int drmAgpVendorId(int fd) +{ + drm_agp_info_t i; + + if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0; + return i.id_vendor; +} + +unsigned int drmAgpDeviceId(int fd) +{ + drm_agp_info_t i; + + if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0; + return i.id_device; +} + int drmError(int err, const char *label) { switch (err) { diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index 44d75c487..2ea6c7215 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -14,7 +14,8 @@ L_TARGET := libdrm.a L_OBJS := init.o memory.o proc.o auth.o context.o drawable.o bufs.o \ - lists.o lock.o ioctl.o fops.o vm.o dma.o + lists.o lock.o ioctl.o fops.o vm.o dma.o ctxbitmap.o \ + agpsupport.o M_OBJS := @@ -26,6 +27,14 @@ ifdef CONFIG_DRM_TDFX M_OBJS += tdfx.o endif +ifdef CONFIG_DRM_MGA +M_OBJS += mga.o +endif + +ifdef CONFIG_DRM_R128 +M_OBJS += r128.o +endif + include $(TOPDIR)/Rules.make gamma.o: gamma_drv.o gamma_dma.o $(L_TARGET) @@ -33,3 +42,10 @@ gamma.o: gamma_drv.o gamma_dma.o $(L_TARGET) tdfx.o: tdfx_drv.o tdfx_context.o $(L_TARGET) $(LD) $(LD_RFLAG) -r -o $@ tdfx_drv.o tdfx_context.o -L. -ldrm + +i810.o: i810_drv.o i810_context.o $(L_TARGET) + $(LD) $(LD_RFLAG) -r -o $@ i810_drv.o i810_bufs.o i810_dma.o i810_context.o -L. -ldrm + +mga.o: mga_drv.o mga_context.o mga_dma.o mga_bufs.o $(L_TARGET) + $(LD) $(LD_RFLAG) -r -o $@ mga_drv.o mga_bufs.o mga_dma.o mga_context.o mga_state.o -L. -ldrm + diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 312fba36f..f8e78eabd 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -48,8 +48,12 @@ #ifdef CONFIG_MTRR #include #endif +#ifdef DRM_AGP +#include +#include +#endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) -#include +#include #include #endif #include "drm.h" @@ -69,21 +73,27 @@ #define DRM_FLAG_DEBUG 0x01 #define DRM_FLAG_NOCTX 0x02 -#define DRM_MEM_DMA 0 -#define DRM_MEM_SAREA 1 -#define DRM_MEM_DRIVER 2 -#define DRM_MEM_MAGIC 3 -#define DRM_MEM_IOCTLS 4 -#define DRM_MEM_MAPS 5 -#define DRM_MEM_VMAS 6 -#define DRM_MEM_BUFS 7 -#define DRM_MEM_SEGS 8 -#define DRM_MEM_PAGES 9 -#define DRM_MEM_FILES 10 -#define DRM_MEM_QUEUES 11 -#define DRM_MEM_CMDS 12 -#define DRM_MEM_MAPPINGS 13 -#define DRM_MEM_BUFLISTS 14 +#define DRM_MEM_DMA 0 +#define DRM_MEM_SAREA 1 +#define DRM_MEM_DRIVER 2 +#define DRM_MEM_MAGIC 3 +#define DRM_MEM_IOCTLS 4 +#define DRM_MEM_MAPS 5 +#define DRM_MEM_VMAS 6 +#define DRM_MEM_BUFS 7 +#define DRM_MEM_SEGS 8 +#define DRM_MEM_PAGES 9 +#define DRM_MEM_FILES 10 +#define DRM_MEM_QUEUES 11 +#define DRM_MEM_CMDS 12 +#define DRM_MEM_MAPPINGS 13 +#define DRM_MEM_BUFLISTS 14 +#define DRM_MEM_AGPLISTS 15 +#define DRM_MEM_TOTALAGP 16 +#define DRM_MEM_BOUNDAGP 17 +#define DRM_MEM_CTXBITMAP 18 + +#define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8) /* Backward compatibility section */ /* _PAGE_WT changed to _PAGE_PWT in 2.2.6 */ @@ -235,6 +245,7 @@ typedef struct drm_buf { int used; /* Amount of buffer in use (for DMA) */ unsigned long offset; /* Byte offset (used internally) */ void *address; /* Address of buffer */ + unsigned long bus_address; /* Bus address of buffer */ struct drm_buf *next; /* Kernel-only: used for free list */ __volatile__ int waiting; /* On kernel DMA queue */ __volatile__ int pending; /* On hardware DMA queue */ @@ -250,6 +261,11 @@ typedef struct drm_buf { DRM_LIST_PRIO = 4, DRM_LIST_RECLAIM = 5 } list; /* Which list we're on */ + + + void *dev_private; + int dev_priv_size; + #if DRM_DMA_HISTOGRAM cycles_t time_queued; /* Queued to kernel DMA queue */ cycles_t time_dispatched; /* Dispatched to hardware */ @@ -376,6 +392,9 @@ typedef struct drm_device_dma { int page_count; unsigned long *pagelist; unsigned long byte_count; + enum { + _DRM_DMA_USE_AGP = 0x01 + } flags; /* DMA support */ drm_buf_t *this_buffer; /* Buffer being sent */ @@ -384,6 +403,41 @@ typedef struct drm_device_dma { wait_queue_head_t waiting; /* Processes waiting on free bufs */ } drm_device_dma_t; +#ifdef DRM_AGP +typedef struct drm_agp_mem { + unsigned long handle; + agp_memory *memory; + unsigned long bound; /* address */ + int pages; + struct drm_agp_mem *prev; + struct drm_agp_mem *next; +} drm_agp_mem_t; + +typedef struct drm_agp_head { + agp_kern_info agp_info; + const char *chipset; + drm_agp_mem_t *memory; + unsigned long mode; + int enabled; + int acquired; + unsigned long base; + int agp_mtrr; +} drm_agp_head_t; + +typedef struct { + void (*free_memory)(agp_memory *); + agp_memory *(*allocate_memory)(size_t, u32); + int (*bind_memory)(agp_memory *, off_t); + int (*unbind_memory)(agp_memory *); + void (*enable)(u32); + int (*acquire)(void); + void (*release)(void); + void (*copy_info)(agp_kern_info *); +} drm_agp_func_t; + +extern drm_agp_func_t drm_agp; +#endif + typedef struct drm_device { const char *name; /* Simple driver name */ char *unique; /* Unique identifier: e.g., busid */ @@ -462,6 +516,12 @@ typedef struct drm_device { struct fasync_struct *buf_async;/* Processes waiting for SIGIO */ wait_queue_head_t buf_readers; /* Processes waiting to read */ wait_queue_head_t buf_writers; /* Processes waiting to ctx switch */ + +#ifdef DRM_AGP + drm_agp_head_t *agp; +#endif + unsigned long *ctx_bitmap; + void *dev_private; } drm_device_t; @@ -533,6 +593,14 @@ extern void drm_free_pages(unsigned long address, int order, extern void *drm_ioremap(unsigned long offset, unsigned long size); extern void drm_ioremapfree(void *pt, unsigned long size); +#ifdef DRM_AGP +extern agp_memory *drm_alloc_agp(int pages, u32 type); +extern int drm_free_agp(agp_memory *handle, int pages); +extern int drm_bind_agp(agp_memory *handle, unsigned int start); +extern int drm_unbind_agp(agp_memory *handle); +#endif + + /* Buffer management support (bufs.c) */ extern int drm_order(unsigned long size); extern int drm_addmap(struct inode *inode, struct file *filp, @@ -642,5 +710,32 @@ extern int drm_flush_unblock(drm_device_t *dev, int context, drm_lock_flags_t flags); extern int drm_flush_block_and_flush(drm_device_t *dev, int context, drm_lock_flags_t flags); + + /* Context Bitmap support (ctxbitmap.c) */ +extern int drm_ctxbitmap_init(drm_device_t *dev); +extern void drm_ctxbitmap_cleanup(drm_device_t *dev); +extern int drm_ctxbitmap_next(drm_device_t *dev); +extern void drm_ctxbitmap_free(drm_device_t *dev, int ctx_handle); + +#ifdef DRM_AGP + /* AGP/GART support (agpsupport.c) */ +extern drm_agp_head_t *drm_agp_init(void); +extern int drm_agp_acquire(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_agp_release(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_agp_enable(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_agp_info(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_agp_alloc(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_agp_free(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_agp_unbind(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_agp_bind(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +#endif #endif #endif diff --git a/linux-core/i810_dma.c b/linux-core/i810_dma.c index 09959b657..30fda5b8b 100644 --- a/linux-core/i810_dma.c +++ b/linux-core/i810_dma.c @@ -25,8 +25,9 @@ * * Authors: Rickard E. (Rik) Faith * Jeff Hartmann + * Keith Whitwell * - * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/i810_dma.c,v 1.1 2000/02/11 17:26:04 dawes Exp $ + * $XFree86$ * */ @@ -36,6 +37,9 @@ #include /* For task queue support */ +#define I810_BUF_FREE 1 +#define I810_BUF_USED 0 + #define I810_REG(reg) 2 #define I810_BASE(reg) ((unsigned long) \ dev->maplist[I810_REG(reg)]->handle) @@ -43,544 +47,457 @@ #define I810_DEREF(reg) *(__volatile__ int *)I810_ADDR(reg) #define I810_READ(reg) I810_DEREF(reg) #define I810_WRITE(reg,val) do { I810_DEREF(reg) = val; } while (0) - -void i810_dma_init(drm_device_t *dev) +#define I810_DEREF16(reg) *(__volatile__ u16 *)I810_ADDR(reg) +#define I810_READ16(reg) I810_DEREF16(reg) +#define I810_WRITE16(reg,val) do { I810_DEREF16(reg) = val; } while (0) + +#define RING_LOCALS unsigned int outring, ringmask; volatile char *virt; + +#define BEGIN_LP_RING(n) do { \ + if (I810_VERBOSE) \ + DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n", \ + n, __FUNCTION__); \ + if (dev_priv->ring.space < n*4) \ + i810_wait_ring(dev, n*4); \ + dev_priv->ring.space -= n*4; \ + outring = dev_priv->ring.tail; \ + ringmask = dev_priv->ring.tail_mask; \ + virt = dev_priv->ring.virtual_start; \ +} while (0) + +#define ADVANCE_LP_RING() do { \ + if (I810_VERBOSE) DRM_DEBUG("ADVANCE_LP_RING\n"); \ + dev_priv->ring.tail = outring; \ + I810_WRITE(LP_RING + RING_TAIL, outring); \ +} while(0) + +#define OUT_RING(n) do { \ + if (I810_VERBOSE) DRM_DEBUG(" OUT_RING %x\n", (int)(n)); \ + *(volatile unsigned int *)(virt + outring) = n; \ + outring += 4; \ + outring &= ringmask; \ +} while (0); + +static inline void i810_print_status_page(drm_device_t *dev) { - printk(KERN_INFO "i810_dma_init\n"); + drm_device_dma_t *dma = dev->dma; + drm_i810_private_t *dev_priv = dev->dev_private; + u32 *temp = (u32 *)dev_priv->hw_status_page; + int i; + + DRM_DEBUG( "hw_status: Interrupt Status : %x\n", temp[0]); + DRM_DEBUG( "hw_status: LpRing Head ptr : %x\n", temp[1]); + DRM_DEBUG( "hw_status: IRing Head ptr : %x\n", temp[2]); + DRM_DEBUG( "hw_status: Reserved : %x\n", temp[3]); + DRM_DEBUG( "hw_status: Driver Counter : %d\n", temp[5]); + for(i = 6; i < dma->buf_count + 6; i++) { + DRM_DEBUG( "buffer status idx : %d used: %d\n", i - 6, temp[i]); + } } -void i810_dma_cleanup(drm_device_t *dev) +static drm_buf_t *i810_freelist_get(drm_device_t *dev) { - printk(KERN_INFO "i810_dma_cleanup\n"); + drm_device_dma_t *dma = dev->dma; + int i; + int used; + + /* Linear search might not be the best solution */ + + for (i = 0; i < dma->buf_count; i++) { + drm_buf_t *buf = dma->buflist[ i ]; + drm_i810_buf_priv_t *buf_priv = buf->dev_private; + /* In use is already a pointer */ + used = cmpxchg(buf_priv->in_use, I810_BUF_FREE, + I810_BUF_USED); + if(used == I810_BUF_FREE) { + return buf; + } + } + return NULL; } -static inline void i810_dma_dispatch(drm_device_t *dev, unsigned long address, - unsigned long length) +/* This should only be called if the buffer is not sent to the hardware + * yet, the hardware updates in use for us once its on the ring buffer. + */ + +static int i810_freelist_put(drm_device_t *dev, drm_buf_t *buf) { - printk(KERN_INFO "i810_dma_dispatch\n"); + drm_i810_buf_priv_t *buf_priv = buf->dev_private; + int used; + + /* In use is already a pointer */ + used = cmpxchg(buf_priv->in_use, I810_BUF_USED, I810_BUF_FREE); + if(used != I810_BUF_USED) { + DRM_ERROR("Freeing buffer thats not in use : %d\n", buf->idx); + return -EINVAL; + } + + return 0; } -static inline void i810_dma_quiescent(drm_device_t *dev) +static int i810_dma_get_buffers(drm_device_t *dev, drm_dma_t *d) { + int i; + drm_buf_t *buf; + + for (i = d->granted_count; i < d->request_count; i++) { + buf = i810_freelist_get(dev); + if (!buf) break; + buf->pid = current->pid; + copy_to_user_ret(&d->request_indices[i], + &buf->idx, + sizeof(buf->idx), + -EFAULT); + copy_to_user_ret(&d->request_sizes[i], + &buf->total, + sizeof(buf->total), + -EFAULT); + ++d->granted_count; + } + return 0; } -static inline void i810_dma_ready(drm_device_t *dev) +static unsigned long i810_alloc_page(drm_device_t *dev) { - i810_dma_quiescent(dev); - printk(KERN_INFO "i810_dma_ready\n"); + unsigned long address; + + address = __get_free_page(GFP_KERNEL); + if(address == 0UL) + return 0; + + atomic_inc(&mem_map[MAP_NR((void *) address)].count); + set_bit(PG_locked, &mem_map[MAP_NR((void *) address)].flags); + + return address; } -static inline int i810_dma_is_ready(drm_device_t *dev) +static void i810_free_page(drm_device_t *dev, unsigned long page) { - - i810_dma_quiescent(dev); - - printk(KERN_INFO "i810_dma_is_ready\n"); - return 1; + if(page == 0UL) + return; + + atomic_dec(&mem_map[MAP_NR((void *) page)].count); + clear_bit(PG_locked, &mem_map[MAP_NR((void *) page)].flags); + wake_up(&mem_map[MAP_NR((void *) page)].wait); + free_page(page); + return; } - -static void i810_dma_service(int irq, void *device, struct pt_regs *regs) +static int i810_dma_cleanup(drm_device_t *dev) { - drm_device_t *dev = (drm_device_t *)device; - drm_device_dma_t *dma = dev->dma; - - atomic_inc(&dev->total_irq); - if (i810_dma_is_ready(dev)) { - /* Free previous buffer */ - if (test_and_set_bit(0, &dev->dma_flag)) { - atomic_inc(&dma->total_missed_free); - return; + if(dev->dev_private) { + drm_i810_private_t *dev_priv = + (drm_i810_private_t *) dev->dev_private; + + if(dev_priv->ring.virtual_start) { + drm_ioremapfree((void *) dev_priv->ring.virtual_start, + dev_priv->ring.Size); } - if (dma->this_buffer) { - drm_free_buffer(dev, dma->this_buffer); - dma->this_buffer = NULL; + if(dev_priv->hw_status_page != 0UL) { + i810_free_page(dev, dev_priv->hw_status_page); + /* Need to rewrite hardware status page */ + I810_WRITE(0x02080, 0x1ffff000); } - clear_bit(0, &dev->dma_flag); - - /* Dispatch new buffer */ - queue_task(&dev->tq, &tq_immediate); - mark_bh(IMMEDIATE_BH); + drm_free(dev->dev_private, sizeof(drm_i810_private_t), + DRM_MEM_DRIVER); + dev->dev_private = NULL; } + return 0; } -/* Only called by i810_dma_schedule. */ -static int i810_do_dma(drm_device_t *dev, int locked) +static int i810_wait_ring(drm_device_t *dev, int n) { - unsigned long address; - unsigned long length; - drm_buf_t *buf; - int retcode = 0; - drm_device_dma_t *dma = dev->dma; -#if DRM_DMA_HISTOGRAM - cycles_t dma_start, dma_stop; -#endif - - if (test_and_set_bit(0, &dev->dma_flag)) { - atomic_inc(&dma->total_missed_dma); - return -EBUSY; - } - -#if DRM_DMA_HISTOGRAM - dma_start = get_cycles(); -#endif - - if (!dma->next_buffer) { - DRM_ERROR("No next_buffer\n"); - clear_bit(0, &dev->dma_flag); - return -EINVAL; - } - - buf = dma->next_buffer; - address = (unsigned long)buf->bus_address; - length = buf->used; + drm_i810_private_t *dev_priv = dev->dev_private; + drm_i810_ring_buffer_t *ring = &(dev_priv->ring); + int iters = 0; + unsigned long end; + + end = jiffies + (HZ*3); + while (ring->space < n) { + int i; - - DRM_DEBUG("context %d, buffer %d (%ld bytes)\n", - buf->context, buf->idx, length); - - if (buf->list == DRM_LIST_RECLAIM) { - drm_clear_next_buffer(dev); - drm_free_buffer(dev, buf); - clear_bit(0, &dev->dma_flag); - return -EINVAL; - } - - if (!length) { - DRM_ERROR("0 length buffer\n"); - drm_clear_next_buffer(dev); - drm_free_buffer(dev, buf); - clear_bit(0, &dev->dma_flag); - return 0; - } - - if (!i810_dma_is_ready(dev)) { - clear_bit(0, &dev->dma_flag); - return -EBUSY; - } - - if (buf->while_locked) { - if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { - DRM_ERROR("Dispatching buffer %d from pid %d" - " \"while locked\", but no lock held\n", - buf->idx, buf->pid); - } - } else { - if (!locked && !drm_lock_take(&dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT)) { - atomic_inc(&dma->total_missed_lock); - clear_bit(0, &dev->dma_flag); - return -EBUSY; + ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR; + ring->space = ring->head - (ring->tail+8); + + if (ring->space < 0) ring->space += ring->Size; + + iters++; + if((signed)(end - jiffies) <= 0) { + DRM_ERROR("space: %d wanted %d\n", ring->space, n); + DRM_ERROR("lockup\n"); + goto out_wait_ring; } - } - - if (dev->last_context != buf->context - && !(dev->queuelist[buf->context]->flags - & _DRM_CONTEXT_PRESERVED)) { - /* PRE: dev->last_context != buf->context */ - if (drm_context_switch(dev, dev->last_context, buf->context)) { - drm_clear_next_buffer(dev); - drm_free_buffer(dev, buf); - } - retcode = -EBUSY; - goto cleanup; - - /* POST: we will wait for the context - switch and will dispatch on a later call - when dev->last_context == buf->context. - NOTE WE HOLD THE LOCK THROUGHOUT THIS - TIME! */ - } - - drm_clear_next_buffer(dev); - buf->pending = 1; - buf->waiting = 0; - buf->list = DRM_LIST_PEND; -#if DRM_DMA_HISTOGRAM - buf->time_dispatched = get_cycles(); -#endif - i810_dma_dispatch(dev, address, length); - drm_free_buffer(dev, dma->this_buffer); - dma->this_buffer = buf; - - atomic_add(length, &dma->total_bytes); - atomic_inc(&dma->total_dmas); - - if (!buf->while_locked && !dev->context_flag && !locked) { - if (drm_lock_free(dev, &dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT)) { - DRM_ERROR("\n"); - } + for (i = 0 ; i < 2000 ; i++) ; } -cleanup: - - clear_bit(0, &dev->dma_flag); -#if DRM_DMA_HISTOGRAM - dma_stop = get_cycles(); - atomic_inc(&dev->histo.dma[drm_histogram_slot(dma_stop - dma_start)]); -#endif - - return retcode; -} - -static void i810_dma_schedule_timer_wrapper(unsigned long dev) -{ - i810_dma_schedule((drm_device_t *)dev, 0); +out_wait_ring: + return iters; } -static void i810_dma_schedule_tq_wrapper(void *dev) +static void i810_kernel_lost_context(drm_device_t *dev) { - i810_dma_schedule(dev, 0); + drm_i810_private_t *dev_priv = dev->dev_private; + drm_i810_ring_buffer_t *ring = &(dev_priv->ring); + + ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR; + ring->tail = I810_READ(LP_RING + RING_TAIL); + ring->space = ring->head - (ring->tail+8); + if (ring->space < 0) ring->space += ring->Size; } -int i810_dma_schedule(drm_device_t *dev, int locked) +static int i810_freelist_init(drm_device_t *dev) { - int next; - drm_queue_t *q; - drm_buf_t *buf; - int retcode = 0; - int processed = 0; - int missed; - int expire = 20; - drm_device_dma_t *dma = dev->dma; -#if DRM_DMA_HISTOGRAM - cycles_t schedule_start; -#endif - - if (test_and_set_bit(0, &dev->interrupt_flag)) { - /* Not reentrant */ - atomic_inc(&dma->total_missed_sched); - return -EBUSY; - } - missed = atomic_read(&dma->total_missed_sched); - -#if DRM_DMA_HISTOGRAM - schedule_start = get_cycles(); -#endif - -again: - if (dev->context_flag) { - clear_bit(0, &dev->interrupt_flag); - return -EBUSY; - } - if (dma->next_buffer) { - /* Unsent buffer that was previously - selected, but that couldn't be sent - because the lock could not be obtained - or the DMA engine wasn't ready. Try - again. */ - atomic_inc(&dma->total_tried); - if (!(retcode = i810_do_dma(dev, locked))) { - atomic_inc(&dma->total_hit); - ++processed; - } - } else { - do { - next = drm_select_queue(dev, - i810_dma_schedule_timer_wrapper); - if (next >= 0) { - q = dev->queuelist[next]; - buf = drm_waitlist_get(&q->waitlist); - dma->next_buffer = buf; - dma->next_queue = q; - if (buf && buf->list == DRM_LIST_RECLAIM) { - drm_clear_next_buffer(dev); - drm_free_buffer(dev, buf); - } - } - } while (next >= 0 && !dma->next_buffer); - if (dma->next_buffer) { - if (!(retcode = i810_do_dma(dev, locked))) { - ++processed; - } - } + drm_device_dma_t *dma = dev->dma; + drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; + u8 *hw_status = (u8 *)dev_priv->hw_status_page; + int i; + int my_idx = 24; + + if(dma->buf_count > 1019) { + /* Not enough space in the status page for the freelist */ + return -EINVAL; } - if (--expire) { - if (missed != atomic_read(&dma->total_missed_sched)) { - atomic_inc(&dma->total_lost); - if (i810_dma_is_ready(dev)) goto again; - } - if (processed && i810_dma_is_ready(dev)) { - atomic_inc(&dma->total_lost); - processed = 0; - goto again; - } + for (i = 0; i < dma->buf_count; i++) { + drm_buf_t *buf = dma->buflist[ i ]; + drm_i810_buf_priv_t *buf_priv = buf->dev_private; + + buf_priv->in_use = hw_status + my_idx; + DRM_DEBUG("buf_priv->in_use : %p\n", buf_priv->in_use); + *buf_priv->in_use = I810_BUF_FREE; + buf_priv->my_use_idx = my_idx; + my_idx += 4; } - - clear_bit(0, &dev->interrupt_flag); - -#if DRM_DMA_HISTOGRAM - atomic_inc(&dev->histo.schedule[drm_histogram_slot(get_cycles() - - schedule_start)]); -#endif - return retcode; + return 0; } -static int i810_dma_priority(drm_device_t *dev, drm_dma_t *d) +static int i810_dma_initialize(drm_device_t *dev, + drm_i810_private_t *dev_priv, + drm_i810_init_t *init) { - unsigned long address; - unsigned long length; - int must_free = 0; - int retcode = 0; - int i; - int idx; - drm_buf_t *buf; - drm_buf_t *last_buf = NULL; - drm_device_dma_t *dma = dev->dma; - DECLARE_WAITQUEUE(entry, current); - - /* Turn off interrupt handling */ - while (test_and_set_bit(0, &dev->interrupt_flag)) { - schedule(); - if (signal_pending(current)) return -EINTR; - } - if (!(d->flags & _DRM_DMA_WHILE_LOCKED)) { - while (!drm_lock_take(&dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT)) { - schedule(); - if (signal_pending(current)) { - clear_bit(0, &dev->interrupt_flag); - return -EINTR; - } - } - ++must_free; - } - atomic_inc(&dma->total_prio); - - for (i = 0; i < d->send_count; i++) { - idx = d->send_indices[i]; - if (idx < 0 || idx >= dma->buf_count) { - DRM_ERROR("Index %d (of %d max)\n", - d->send_indices[i], dma->buf_count - 1); - continue; - } - buf = dma->buflist[ idx ]; - if (buf->pid != current->pid) { - DRM_ERROR("Process %d using buffer owned by %d\n", - current->pid, buf->pid); - retcode = -EINVAL; - goto cleanup; - } - if (buf->list != DRM_LIST_NONE) { - DRM_ERROR("Process %d using %d's buffer on list %d\n", - current->pid, buf->pid, buf->list); - retcode = -EINVAL; - goto cleanup; - } - /* This isn't a race condition on - buf->list, since our concern is the - buffer reclaim during the time the - process closes the /dev/drm? handle, so - it can't also be doing DMA. */ - buf->list = DRM_LIST_PRIO; - buf->used = d->send_sizes[i]; - buf->context = d->context; - buf->while_locked = d->flags & _DRM_DMA_WHILE_LOCKED; - address = (unsigned long)buf->address; - length = buf->used; - if (!length) { - DRM_ERROR("0 length buffer\n"); - } - if (buf->pending) { - DRM_ERROR("Sending pending buffer:" - " buffer %d, offset %d\n", - d->send_indices[i], i); - retcode = -EINVAL; - goto cleanup; - } - if (buf->waiting) { - DRM_ERROR("Sending waiting buffer:" - " buffer %d, offset %d\n", - d->send_indices[i], i); - retcode = -EINVAL; - goto cleanup; - } - buf->pending = 1; - - if (dev->last_context != buf->context - && !(dev->queuelist[buf->context]->flags - & _DRM_CONTEXT_PRESERVED)) { - add_wait_queue(&dev->context_wait, &entry); - current->state = TASK_INTERRUPTIBLE; - /* PRE: dev->last_context != buf->context */ - drm_context_switch(dev, dev->last_context, - buf->context); - /* POST: we will wait for the context - switch and will dispatch on a later call - when dev->last_context == buf->context. - NOTE WE HOLD THE LOCK THROUGHOUT THIS - TIME! */ - schedule(); - current->state = TASK_RUNNING; - remove_wait_queue(&dev->context_wait, &entry); - if (signal_pending(current)) { - retcode = -EINTR; - goto cleanup; - } - if (dev->last_context != buf->context) { - DRM_ERROR("Context mismatch: %d %d\n", - dev->last_context, - buf->context); - } - } - -#if DRM_DMA_HISTOGRAM - buf->time_queued = get_cycles(); - buf->time_dispatched = buf->time_queued; -#endif - i810_dma_dispatch(dev, address, length); - if (drm_lock_free(dev, &dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT)) { - DRM_ERROR("\n"); - } - - atomic_add(length, &dma->total_bytes); - atomic_inc(&dma->total_dmas); - - if (last_buf) { - drm_free_buffer(dev, last_buf); - } - last_buf = buf; - } + drm_map_t *sarea_map; + dev->dev_private = (void *) dev_priv; + memset(dev_priv, 0, sizeof(drm_i810_private_t)); -cleanup: - if (last_buf) { - i810_dma_ready(dev); - drm_free_buffer(dev, last_buf); + if (init->ring_map_idx >= dev->map_count || + init->buffer_map_idx >= dev->map_count) { + i810_dma_cleanup(dev); + DRM_ERROR("ring_map or buffer_map are invalid\n"); + return -EINVAL; } - - if (must_free && !dev->context_flag) { - if (drm_lock_free(dev, &dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT)) { - DRM_ERROR("\n"); - } + + dev_priv->ring_map_idx = init->ring_map_idx; + dev_priv->buffer_map_idx = init->buffer_map_idx; + sarea_map = dev->maplist[0]; + dev_priv->sarea_priv = (drm_i810_sarea_t *) + ((u8 *)sarea_map->handle + + init->sarea_priv_offset); + + atomic_set(&dev_priv->flush_done, 0); + init_waitqueue_head(&dev_priv->flush_queue); + + dev_priv->ring.Start = init->ring_start; + dev_priv->ring.End = init->ring_end; + dev_priv->ring.Size = init->ring_size; + dev_priv->ring.virtual_start = drm_ioremap(dev->agp->base + + init->ring_start, + init->ring_size); + dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; + + if (dev_priv->ring.virtual_start == NULL) { + i810_dma_cleanup(dev); + DRM_ERROR("can not ioremap virtual address for" + " ring buffer\n"); + return -ENOMEM; } - clear_bit(0, &dev->interrupt_flag); - return retcode; + + /* Program Hardware Status Page */ + dev_priv->hw_status_page = i810_alloc_page(dev); + memset((void *) dev_priv->hw_status_page, 0, PAGE_SIZE); + if(dev_priv->hw_status_page == 0UL) { + i810_dma_cleanup(dev); + DRM_ERROR("Can not allocate hardware status page\n"); + return -ENOMEM; + } + DRM_DEBUG("hw status page @ %lx\n", dev_priv->hw_status_page); + + I810_WRITE(0x02080, virt_to_bus((void *)dev_priv->hw_status_page)); + DRM_DEBUG("Enabled hardware status page\n"); + + /* Now we need to init our freelist */ + if(i810_freelist_init(dev) != 0) { + i810_dma_cleanup(dev); + DRM_ERROR("Not enough space in the status page for" + " the freelist\n"); + return -ENOMEM; + } + return 0; } -static int i810_dma_send_buffers(drm_device_t *dev, drm_dma_t *d) +int i810_dma_init(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) { - DECLARE_WAITQUEUE(entry, current); - drm_buf_t *last_buf = NULL; - int retcode = 0; - drm_device_dma_t *dma = dev->dma; - - if (d->flags & _DRM_DMA_BLOCK) { - last_buf = dma->buflist[d->send_indices[d->send_count-1]]; - add_wait_queue(&last_buf->dma_wait, &entry); - } + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_i810_private_t *dev_priv; + drm_i810_init_t init; + int retcode = 0; - if ((retcode = drm_dma_enqueue(dev, d))) { - if (d->flags & _DRM_DMA_BLOCK) - remove_wait_queue(&last_buf->dma_wait, &entry); - return retcode; - } - - i810_dma_schedule(dev, 0); + copy_from_user_ret(&init, (drm_i810_init_t *)arg, + sizeof(init), -EFAULT); - if (d->flags & _DRM_DMA_BLOCK) { - DRM_DEBUG("%d waiting\n", current->pid); - current->state = TASK_INTERRUPTIBLE; - for (;;) { - if (!last_buf->waiting - && !last_buf->pending) - break; /* finished */ - schedule(); - if (signal_pending(current)) { - retcode = -EINTR; /* Can't restart */ - break; - } - } - current->state = TASK_RUNNING; - DRM_DEBUG("%d running\n", current->pid); - remove_wait_queue(&last_buf->dma_wait, &entry); - if (!retcode - || (last_buf->list==DRM_LIST_PEND && !last_buf->pending)) { - if (!waitqueue_active(&last_buf->dma_wait)) { - drm_free_buffer(dev, last_buf); - } - } - if (retcode) { - DRM_ERROR("ctx%d w%d p%d c%d i%d l%d %d/%d\n", - d->context, - last_buf->waiting, - last_buf->pending, - DRM_WAITCOUNT(dev, d->context), - last_buf->idx, - last_buf->list, - last_buf->pid, - current->pid); - } + switch(init.func) { + case I810_INIT_DMA: + dev_priv = drm_alloc(sizeof(drm_i810_private_t), + DRM_MEM_DRIVER); + if(dev_priv == NULL) return -ENOMEM; + retcode = i810_dma_initialize(dev, dev_priv, &init); + break; + case I810_CLEANUP_DMA: + retcode = i810_dma_cleanup(dev); + break; + default: + retcode = -EINVAL; + break; } - return retcode; + + return retcode; } -int i810_dma(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) +static void i810_dma_dispatch_general(drm_device_t *dev, drm_buf_t *buf, + int used ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - drm_device_dma_t *dma = dev->dma; - int retcode = 0; - drm_dma_t d; - - printk("i810_dma start\n"); - copy_from_user_ret(&d, (drm_dma_t *)arg, sizeof(d), -EFAULT); - DRM_DEBUG("%d %d: %d send, %d req\n", - current->pid, d.context, d.send_count, d.request_count); + drm_i810_private_t *dev_priv = dev->dev_private; + drm_i810_buf_priv_t *buf_priv = buf->dev_private; + unsigned long address = (unsigned long)buf->bus_address; + unsigned long start = address - dev->agp->base; + RING_LOCALS; + + dev_priv->counter++; + DRM_DEBUG( "dispatch counter : %ld\n", dev_priv->counter); + DRM_DEBUG( "i810_dma_dispatch\n"); + DRM_DEBUG( "start : 0x%lx\n", start); + DRM_DEBUG( "used : 0x%x\n", used); + DRM_DEBUG( "start + used - 4 : 0x%lx\n", start + used - 4); + i810_kernel_lost_context(dev); + + BEGIN_LP_RING(10); + OUT_RING( CMD_OP_BATCH_BUFFER ); + OUT_RING( start | BB1_PROTECTED ); + OUT_RING( start + used - 4 ); + OUT_RING( CMD_STORE_DWORD_IDX ); + OUT_RING( 20 ); + OUT_RING( dev_priv->counter ); + OUT_RING( CMD_STORE_DWORD_IDX ); + OUT_RING( buf_priv->my_use_idx ); + OUT_RING( I810_BUF_FREE ); + OUT_RING( CMD_REPORT_HEAD ); + ADVANCE_LP_RING(); +} - if (d.context == DRM_KERNEL_CONTEXT || d.context >= dev->queue_slots) { - DRM_ERROR("Process %d using context %d\n", - current->pid, d.context); - return -EINVAL; - } +static void i810_dma_dispatch_vertex(drm_device_t *dev, + drm_buf_t *buf, + int discard, + int used) +{ + drm_i810_private_t *dev_priv = dev->dev_private; + drm_i810_buf_priv_t *buf_priv = buf->dev_private; + drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_clip_rect_t *box = sarea_priv->boxes; + int nbox = sarea_priv->nbox; + unsigned long address = (unsigned long)buf->bus_address; + unsigned long start = address - dev->agp->base; + int i = 0; + RING_LOCALS; - 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, d.send_count, dma->buf_count); - return -EINVAL; - } - 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 (nbox > I810_NR_SAREA_CLIPRECTS) + nbox = I810_NR_SAREA_CLIPRECTS; + + DRM_DEBUG("dispatch vertex addr 0x%lx, used 0x%x nbox %d\n", + address, used, nbox); + + dev_priv->counter++; + DRM_DEBUG( "dispatch counter : %ld\n", dev_priv->counter); + DRM_DEBUG( "i810_dma_dispatch\n"); + DRM_DEBUG( "start : %lx\n", start); + DRM_DEBUG( "used : %d\n", used); + DRM_DEBUG( "start + used - 4 : %ld\n", start + used - 4); + i810_kernel_lost_context(dev); + + if (used) { + do { + if (i < nbox) { + BEGIN_LP_RING(4); + OUT_RING( GFX_OP_SCISSOR | SC_UPDATE_SCISSOR | + SC_ENABLE ); + OUT_RING( GFX_OP_SCISSOR_INFO ); + OUT_RING( box[i].x1 | (box[i].y1 << 16) ); + OUT_RING( (box[i].x2-1) | ((box[i].y2-1)<<16) ); + ADVANCE_LP_RING(); + } + + BEGIN_LP_RING(4); + OUT_RING( CMD_OP_BATCH_BUFFER ); + OUT_RING( start | BB1_PROTECTED ); + OUT_RING( start + used - 4 ); + OUT_RING( 0 ); + ADVANCE_LP_RING(); + + } while (++i < nbox); } - if (d.send_count) { -#if 0 - if (d.flags & _DRM_DMA_PRIORITY) - retcode = i810_dma_priority(dev, &d); - else - retcode = i810_dma_send_buffers(dev, &d); -#endif - printk("i810_dma priority\n"); + BEGIN_LP_RING(10); + OUT_RING( CMD_STORE_DWORD_IDX ); + OUT_RING( 20 ); + OUT_RING( dev_priv->counter ); + OUT_RING( 0 ); - retcode = i810_dma_priority(dev, &d); + if (discard) { + OUT_RING( CMD_STORE_DWORD_IDX ); + OUT_RING( buf_priv->my_use_idx ); + OUT_RING( I810_BUF_FREE ); + OUT_RING( 0 ); } - d.granted_count = 0; + OUT_RING( CMD_REPORT_HEAD ); + OUT_RING( 0 ); + ADVANCE_LP_RING(); +} - if (!retcode && d.request_count) { - retcode = drm_dma_get_buffers(dev, &d); - } - DRM_DEBUG("%d returning, granted = %d\n", - current->pid, d.granted_count); - copy_to_user_ret((drm_dma_t *)arg, &d, sizeof(d), -EFAULT); +/* Interrupts are only for flushing */ +static void i810_dma_service(int irq, void *device, struct pt_regs *regs) +{ + drm_device_t *dev = (drm_device_t *)device; + u16 temp; + + atomic_inc(&dev->total_irq); + temp = I810_READ16(I810REG_INT_IDENTITY_R); + temp = temp & ~(0x6000); + if(temp != 0) I810_WRITE16(I810REG_INT_IDENTITY_R, + temp); /* Clear all interrupts */ + + queue_task(&dev->tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} - printk("i810_dma end (granted)\n"); - return retcode; +static void i810_dma_task_queue(void *device) +{ + drm_device_t *dev = (drm_device_t *) device; + drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; + + atomic_set(&dev_priv->flush_done, 1); + wake_up_interruptible(&dev_priv->flush_queue); } int i810_irq_install(drm_device_t *dev, int irq) { int retcode; - + u16 temp; + if (!irq) return -EINVAL; down(&dev->struct_sem); @@ -591,6 +508,7 @@ int i810_irq_install(drm_device_t *dev, int irq) dev->irq = irq; up(&dev->struct_sem); + DRM_DEBUG( "Interrupt Install : %d\n", irq); DRM_DEBUG("%d\n", irq); dev->context_flag = 0; @@ -603,12 +521,21 @@ int i810_irq_install(drm_device_t *dev, int irq) dev->tq.next = NULL; dev->tq.sync = 0; - dev->tq.routine = i810_dma_schedule_tq_wrapper; + dev->tq.routine = i810_dma_task_queue; dev->tq.data = dev; - /* Before installing handler */ - /* TODO */ + temp = I810_READ16(I810REG_HWSTAM); + temp = temp & 0x6000; + I810_WRITE16(I810REG_HWSTAM, temp); + + temp = I810_READ16(I810REG_INT_MASK_R); + temp = temp & 0x6000; + I810_WRITE16(I810REG_INT_MASK_R, temp); /* Unmask interrupts */ + temp = I810_READ16(I810REG_INT_ENABLE_R); + temp = temp & 0x6000; + I810_WRITE16(I810REG_INT_ENABLE_R, temp); /* Disable all interrupts */ + /* Install handler */ if ((retcode = request_irq(dev->irq, i810_dma_service, @@ -620,15 +547,18 @@ int i810_irq_install(drm_device_t *dev, int irq) up(&dev->struct_sem); return retcode; } - - /* After installing handler */ - /* TODO */ + temp = I810_READ16(I810REG_INT_ENABLE_R); + temp = temp & 0x6000; + temp = temp | 0x0003; + I810_WRITE16(I810REG_INT_ENABLE_R, + temp); /* Enable bp & user interrupts */ return 0; } int i810_irq_uninstall(drm_device_t *dev) { int irq; + u16 temp; down(&dev->struct_sem); irq = dev->irq; @@ -636,16 +566,25 @@ int i810_irq_uninstall(drm_device_t *dev) up(&dev->struct_sem); if (!irq) return -EINVAL; - + + DRM_DEBUG( "Interrupt UnInstall: %d\n", irq); DRM_DEBUG("%d\n", irq); - - /* TODO : Disable interrupts */ + + temp = I810_READ16(I810REG_INT_IDENTITY_R); + temp = temp & ~(0x6000); + if(temp != 0) I810_WRITE16(I810REG_INT_IDENTITY_R, + temp); /* Clear all interrupts */ + + temp = I810_READ16(I810REG_INT_ENABLE_R); + temp = temp & 0x6000; + I810_WRITE16(I810REG_INT_ENABLE_R, + temp); /* Disable all interrupts */ + free_irq(irq, dev); return 0; } - int i810_control(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -654,8 +593,7 @@ int i810_control(struct inode *inode, struct file *filp, unsigned int cmd, drm_control_t ctl; int retcode; - printk(KERN_INFO "i810_control\n"); - i810_dma_init(dev); + DRM_DEBUG( "i810_control\n"); copy_from_user_ret(&ctl, (drm_control_t *)arg, sizeof(ctl), -EFAULT); @@ -674,20 +612,134 @@ int i810_control(struct inode *inode, struct file *filp, unsigned int cmd, return 0; } +static inline void i810_dma_emit_flush(drm_device_t *dev) +{ + drm_i810_private_t *dev_priv = dev->dev_private; + RING_LOCALS; + + i810_kernel_lost_context(dev); + BEGIN_LP_RING(2); + OUT_RING( CMD_REPORT_HEAD ); + OUT_RING( GFX_OP_USER_INTERRUPT ); + ADVANCE_LP_RING(); +} + +static inline void i810_dma_quiescent_emit(drm_device_t *dev) +{ + drm_i810_private_t *dev_priv = dev->dev_private; + RING_LOCALS; + + i810_kernel_lost_context(dev); + BEGIN_LP_RING(4); + + OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE ); + OUT_RING( CMD_REPORT_HEAD ); + OUT_RING( GFX_OP_USER_INTERRUPT ); + OUT_RING( 0 ); + ADVANCE_LP_RING(); +} + +static void i810_dma_quiescent(drm_device_t *dev) +{ + DECLARE_WAITQUEUE(entry, current); + drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; + unsigned long end; + + if(dev_priv == NULL) { + return; + } + atomic_set(&dev_priv->flush_done, 0); + current->state = TASK_INTERRUPTIBLE; + add_wait_queue(&dev_priv->flush_queue, &entry); + end = jiffies + (HZ*3); + + for (;;) { + i810_dma_quiescent_emit(dev); + if (atomic_read(&dev_priv->flush_done) == 1) break; + if((signed)(end - jiffies) <= 0) { + DRM_ERROR("lockup\n"); + break; + } + schedule_timeout(HZ*3); + if (signal_pending(current)) { + break; + } + } + + current->state = TASK_RUNNING; + remove_wait_queue(&dev_priv->flush_queue, &entry); + + return; +} + +static int i810_flush_queue(drm_device_t *dev) +{ + DECLARE_WAITQUEUE(entry, current); + drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; + unsigned long end; + int ret = 0; + + if(dev_priv == NULL) { + return 0; + } + atomic_set(&dev_priv->flush_done, 0); + current->state = TASK_INTERRUPTIBLE; + add_wait_queue(&dev_priv->flush_queue, &entry); + end = jiffies + (HZ*3); + for (;;) { + i810_dma_emit_flush(dev); + if (atomic_read(&dev_priv->flush_done) == 1) break; + if((signed)(end - jiffies) <= 0) { + DRM_ERROR("lockup\n"); + break; + } + schedule_timeout(HZ*3); + if (signal_pending(current)) { + ret = -EINTR; /* Can't restart */ + break; + } + } + + current->state = TASK_RUNNING; + remove_wait_queue(&dev_priv->flush_queue, &entry); + + return ret; +} + +/* Must be called with the lock held */ +void i810_reclaim_buffers(drm_device_t *dev, pid_t pid) +{ + drm_device_dma_t *dma = dev->dma; + int i; + + if (!dma) return; + if(dev->dev_private == NULL) return; + + i810_flush_queue(dev); + + for (i = 0; i < dma->buf_count; i++) { + drm_buf_t *buf = dma->buflist[ i ]; + drm_i810_buf_priv_t *buf_priv = buf->dev_private; + + if (buf->pid == pid) { + /* Only buffers that need to get reclaimed ever + * get set to free */ + if(buf_priv == NULL) return; + cmpxchg(buf_priv->in_use, + I810_BUF_USED, I810_BUF_FREE); + } + } +} + int i810_lock(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; + DECLARE_WAITQUEUE(entry, current); int ret = 0; drm_lock_t lock; - drm_queue_t *q; -#if DRM_DMA_HISTOGRAM - cycles_t start; - - dev->lck_start = start = get_cycles(); -#endif copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT); @@ -696,16 +748,20 @@ int i810_lock(struct inode *inode, struct file *filp, unsigned int cmd, current->pid, lock.context); return -EINVAL; } + + DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n", + lock.context, current->pid, dev->lock.hw_lock->lock, + lock.flags); - if (lock.context < 0 || lock.context >= dev->queue_count) { + if (lock.context < 0) { return -EINVAL; } - q = dev->queuelist[lock.context]; - - ret = drm_flush_block_and_flush(dev, lock.context, lock.flags); + /* Only one queue: + */ if (!ret) { - if (_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) +#if 0 + if (_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) != lock.context) { long j = jiffies - dev->lock.lock_time; @@ -716,6 +772,7 @@ int i810_lock(struct inode *inode, struct file *filp, unsigned int cmd, schedule_timeout(j); } } +#endif add_wait_queue(&dev->lock.lock_queue, &entry); for (;;) { if (!dev->lock.hw_lock) { @@ -728,13 +785,13 @@ int i810_lock(struct inode *inode, struct file *filp, unsigned int cmd, dev->lock.pid = current->pid; dev->lock.lock_time = jiffies; atomic_inc(&dev->total_locks); - atomic_inc(&q->total_locks); break; /* Got lock */ } /* Contention */ atomic_inc(&dev->total_sleeps); current->state = TASK_INTERRUPTIBLE; + DRM_DEBUG("Calling lock schedule\n"); schedule(); if (signal_pending(current)) { ret = -ERESTARTSYS; @@ -744,19 +801,184 @@ int i810_lock(struct inode *inode, struct file *filp, unsigned int cmd, current->state = TASK_RUNNING; remove_wait_queue(&dev->lock.lock_queue, &entry); } - - drm_flush_unblock(dev, lock.context, lock.flags); /* cleanup phase */ if (!ret) { - if (lock.flags & _DRM_LOCK_READY) - i810_dma_ready(dev); - if (lock.flags & _DRM_LOCK_QUIESCENT) - i810_dma_quiescent(dev); + if (lock.flags & _DRM_LOCK_QUIESCENT) { + DRM_DEBUG("_DRM_LOCK_QUIESCENT\n"); + DRM_DEBUG("fred\n"); + i810_dma_quiescent(dev); + } } + DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock"); + return ret; +} -#if DRM_DMA_HISTOGRAM - atomic_inc(&dev->histo.lacq[drm_histogram_slot(get_cycles() - start)]); -#endif +int i810_flush_ioctl(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_DEBUG("i810_flush_ioctl\n"); + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i810_flush_ioctl called without lock held\n"); + return -EINVAL; + } + + i810_flush_queue(dev); + return 0; +} + +static int i810DmaGeneral(drm_device_t *dev, drm_i810_general_t *args) +{ + drm_device_dma_t *dma = dev->dma; + drm_buf_t *buf = dma->buflist[ args->idx ]; + + if (!args->used) { + i810_freelist_put(dev, buf); + } else { + i810_dma_dispatch_general( dev, buf, args->used ); + atomic_add(args->used, &dma->total_bytes); + atomic_inc(&dma->total_dmas); + } + return 0; +} + +static int i810DmaVertex(drm_device_t *dev, drm_i810_vertex_t *args) +{ + drm_device_dma_t *dma = dev->dma; + drm_buf_t *buf = dma->buflist[ args->idx ]; + i810_dma_dispatch_vertex( dev, buf, args->discard, args->used ); + atomic_add(args->used, &dma->total_bytes); + atomic_inc(&dma->total_dmas); + return 0; +} + +int i810_dma_general(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_i810_general_t general; + drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; + u32 *hw_status = (u32 *)dev_priv->hw_status_page; + drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) + dev_priv->sarea_priv; + + int retcode = 0; - return ret; + copy_from_user_ret(&general, (drm_i810_general_t *)arg, sizeof(general), + -EFAULT); + + DRM_DEBUG("i810 dma general idx %d used %d\n", + general.idx, general.used); + + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i810_dma_general called without lock held\n"); + return -EINVAL; + } + + retcode = i810DmaGeneral(dev, &general); + sarea_priv->last_enqueue = dev_priv->counter-1; + sarea_priv->last_dispatch = (int) hw_status[5]; + + return retcode; +} + +int i810_dma_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_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; + u32 *hw_status = (u32 *)dev_priv->hw_status_page; + drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) + dev_priv->sarea_priv; + drm_i810_vertex_t vertex; + int retcode = 0; + + copy_from_user_ret(&vertex, (drm_i810_vertex_t *)arg, sizeof(vertex), + -EFAULT); + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i810_dma_vertex called without lock held\n"); + return -EINVAL; + } + + DRM_DEBUG("i810 dma vertex, idx %d used %d discard %d\n", + vertex.idx, vertex.used, vertex.discard); + + retcode = i810DmaVertex(dev, &vertex); + sarea_priv->last_enqueue = dev_priv->counter-1; + sarea_priv->last_dispatch = (int) hw_status[5]; + + return retcode; + +} + +int i810_getage(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_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; + u32 *hw_status = (u32 *)dev_priv->hw_status_page; + drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) + dev_priv->sarea_priv; + + sarea_priv->last_dispatch = (int) hw_status[5]; + return 0; +} + +int i810_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_device_dma_t *dma = dev->dma; + int retcode = 0; + drm_dma_t d; + drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; + u32 *hw_status = (u32 *)dev_priv->hw_status_page; + drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) + dev_priv->sarea_priv; + + + copy_from_user_ret(&d, (drm_dma_t *)arg, sizeof(d), -EFAULT); + DRM_DEBUG("%d %d: %d send, %d req\n", + current->pid, d.context, d.send_count, d.request_count); + + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i810_dma called without lock held\n"); + return -EINVAL; + } + + /* Please don't send us buffers. + */ + if (d.send_count != 0) { + DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n", + current->pid, d.send_count); + return -EINVAL; + } + + /* We'll send you buffers. + */ + 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; + } + + d.granted_count = 0; + + if (!retcode && d.request_count) { + retcode = i810_dma_get_buffers(dev, &d); + } + + DRM_DEBUG("i810_dma: %d returning, granted = %d\n", + current->pid, d.granted_count); + + copy_to_user_ret((drm_dma_t *)arg, &d, sizeof(d), -EFAULT); + sarea_priv->last_dispatch = (int) hw_status[5]; + + return retcode; } diff --git a/linux-core/i810_drm.h b/linux-core/i810_drm.h new file mode 100644 index 000000000..0754874c6 --- /dev/null +++ b/linux-core/i810_drm.h @@ -0,0 +1,93 @@ +#ifndef _I810_DRM_H_ +#define _I810_DRM_H_ + +/* WARNING: These defines must be the same as what the Xserver uses. + * if you change them, you must change the defines in the Xserver. + */ + +/* Might one day want to support the client-side ringbuffer code again. + */ +#ifndef _I810_DEFINES_ +#define _I810_DEFINES_ + +#define I810_USE_BATCH 1 +#define I810_DMA_BUF_ORDER 12 +#define I810_DMA_BUF_SZ (1<device = MKDEV(MISC_MAJOR, i810_misc.minor); dev->name = I810_NAME; - printk("doing mem init\n"); + DRM_DEBUG("doing mem init\n"); drm_mem_init(); - printk("doing proc init\n"); + DRM_DEBUG("doing proc init\n"); drm_proc_init(dev); - printk("doing agp init\n"); + DRM_DEBUG("doing agp init\n"); dev->agp = drm_agp_init(); - printk("doing ctxbitmap init\n"); + if(dev->agp == NULL) { + DRM_INFO("The i810 drm module requires the agpgart module" + " to function correctly\nPlease load the agpgart" + " module before you load the i810 module\n"); + drm_proc_cleanup(); + misc_deregister(&i810_misc); + i810_takedown(dev); + return -ENOMEM; + } + DRM_DEBUG("doing ctxbitmap init\n"); if((retcode = drm_ctxbitmap_init(dev))) { DRM_ERROR("Cannot allocate memory for context bitmap.\n"); drm_proc_cleanup(); @@ -386,10 +403,6 @@ int i810_init(void) i810_takedown(dev); return retcode; } -#if 0 - printk("doing i810_dma_init\n"); - i810_dma_init(dev); -#endif DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", I810_NAME, @@ -417,7 +430,6 @@ void i810_cleanup(void) DRM_INFO("Module unloaded\n"); } drm_ctxbitmap_cleanup(dev); - i810_dma_cleanup(dev); i810_takedown(dev); if (dev->agp) { drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS); @@ -484,24 +496,82 @@ int i810_release(struct inode *inode, struct file *filp) drm_device_t *dev = priv->dev; int retcode = 0; - DRM_DEBUG("open_count = %d\n", dev->open_count); - if (!(retcode = drm_release(inode, filp))) { - MOD_DEC_USE_COUNT; - atomic_inc(&dev->total_close); - spin_lock(&dev->count_lock); - if (!--dev->open_count) { - if (atomic_read(&dev->ioctl_count) || dev->blocked) { - DRM_ERROR("Device busy: %d %d\n", - atomic_read(&dev->ioctl_count), - dev->blocked); - spin_unlock(&dev->count_lock); - return -EBUSY; + DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n", + current->pid, dev->device, dev->open_count); + + if (_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) + && dev->lock.pid == current->pid) { + i810_reclaim_buffers(dev, priv->pid); + DRM_ERROR("Process %d dead, freeing lock for context %d\n", + current->pid, + _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); + drm_lock_free(dev, + &dev->lock.hw_lock->lock, + _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); + + /* FIXME: may require heavy-handed reset of + hardware at this point, possibly + processed via a callback to the X + server. */ + } else { + /* The lock is required to reclaim buffers */ + DECLARE_WAITQUEUE(entry, current); + add_wait_queue(&dev->lock.lock_queue, &entry); + for (;;) { + if (!dev->lock.hw_lock) { + /* Device has been unregistered */ + retcode = -EINTR; + break; + } + if (drm_lock_take(&dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT)) { + dev->lock.pid = priv->pid; + dev->lock.lock_time = jiffies; + atomic_inc(&dev->total_locks); + break; /* Got lock */ + } + /* Contention */ + atomic_inc(&dev->total_sleeps); + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (signal_pending(current)) { + retcode = -ERESTARTSYS; + break; } - spin_unlock(&dev->count_lock); - return i810_takedown(dev); } - spin_unlock(&dev->count_lock); + current->state = TASK_RUNNING; + remove_wait_queue(&dev->lock.lock_queue, &entry); + if(!retcode) { + i810_reclaim_buffers(dev, priv->pid); + drm_lock_free(dev, &dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT); + } + } + drm_fasync(-1, filp, 0); + + down(&dev->struct_sem); + if (priv->prev) priv->prev->next = priv->next; + else dev->file_first = priv->next; + if (priv->next) priv->next->prev = priv->prev; + else dev->file_last = priv->prev; + up(&dev->struct_sem); + + drm_free(priv, sizeof(*priv), DRM_MEM_FILES); + MOD_DEC_USE_COUNT; + atomic_inc(&dev->total_close); + spin_lock(&dev->count_lock); + if (!--dev->open_count) { + if (atomic_read(&dev->ioctl_count) || dev->blocked) { + DRM_ERROR("Device busy: %d %d\n", + atomic_read(&dev->ioctl_count), + dev->blocked); + spin_unlock(&dev->count_lock); + return -EBUSY; + } + spin_unlock(&dev->count_lock); + return i810_takedown(dev); } + spin_unlock(&dev->count_lock); return retcode; } @@ -566,8 +636,7 @@ int i810_unlock(struct inode *inode, struct file *filp, unsigned int cmd, atomic_inc(&dev->total_unlocks); if (_DRM_LOCK_IS_CONT(dev->lock.hw_lock->lock)) atomic_inc(&dev->total_contends); - drm_lock_transfer(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT); - i810_dma_schedule(dev, 1); + drm_lock_transfer(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT); if (!dev->context_flag) { if (drm_lock_free(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT)) { diff --git a/linux-core/i810_drv.h b/linux-core/i810_drv.h index 0f5f42bb6..1badd36b8 100644 --- a/linux-core/i810_drv.h +++ b/linux-core/i810_drv.h @@ -32,6 +32,31 @@ #ifndef _I810_DRV_H_ #define _I810_DRV_H_ +typedef struct _drm_i810_ring_buffer{ + int tail_mask; + unsigned long Start; + unsigned long End; + unsigned long Size; + u8 *virtual_start; + int head; + int tail; + int space; +} drm_i810_ring_buffer_t; + +typedef struct drm_i810_private { + int ring_map_idx; + int buffer_map_idx; + + drm_i810_ring_buffer_t ring; + drm_i810_sarea_t *sarea_priv; + + unsigned long hw_status_page; + unsigned long counter; + + atomic_t flush_done; + wait_queue_head_t flush_queue; /* Processes waiting until flush */ +} drm_i810_private_t; + /* i810_drv.c */ extern int i810_init(void); extern void i810_cleanup(void); @@ -54,8 +79,13 @@ extern int i810_control(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int i810_lock(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -extern void i810_dma_init(drm_device_t *dev); -extern void i810_dma_cleanup(drm_device_t *dev); +extern int i810_dma_init(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_flush_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern void i810_reclaim_buffers(drm_device_t *dev, pid_t pid); +extern int i810_getage(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); /* i810_bufs.c */ @@ -72,5 +102,103 @@ extern int i810_mapbufs(struct inode *inode, struct file *filp, extern int i810_addmap(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); + /* i810_context.c */ +extern int i810_resctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_addctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_modctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_getctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_switchctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_newctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_rmctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + +extern int i810_context_switch(drm_device_t *dev, int old, int new); +extern int i810_context_switch_complete(drm_device_t *dev, int new); + + + + +/* Copy the outstanding cliprects for every I810_DMA_VERTEX buffer. + * This can be fixed by emitting directly to the ringbuffer in the + * 'vertex_dma' ioctl. +*/ +typedef struct { + u32 *in_use; + int my_use_idx; +} drm_i810_buf_priv_t; + + +#define I810_DMA_GENERAL 0 +#define I810_DMA_VERTEX 1 +#define I810_DMA_DISCARD 2 /* not used */ + +#define I810_VERBOSE 0 + + +int i810_dma_vertex(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + +int i810_dma_general(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + + +#define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23)) +#define GFX_OP_BREAKPOINT_INTERRUPT ((0<<29)|(1<<23)) +#define CMD_REPORT_HEAD (7<<23) +#define CMD_STORE_DWORD_IDX ((0x21<<23) | 0x1) +#define CMD_OP_BATCH_BUFFER ((0x0<<29)|(0x30<<23)|0x1) + +#define INST_PARSER_CLIENT 0x00000000 +#define INST_OP_FLUSH 0x02000000 +#define INST_FLUSH_MAP_CACHE 0x00000001 + + +#define BB1_START_ADDR_MASK (~0x7) +#define BB1_PROTECTED (1<<0) +#define BB1_UNPROTECTED (0<<0) +#define BB2_END_ADDR_MASK (~0x7) + +#define I810REG_HWSTAM 0x02098 +#define I810REG_INT_IDENTITY_R 0x020a4 +#define I810REG_INT_MASK_R 0x020a8 +#define I810REG_INT_ENABLE_R 0x020a0 + +#define LP_RING 0x2030 +#define HP_RING 0x2040 +#define RING_TAIL 0x00 +#define TAIL_ADDR 0x000FFFF8 +#define RING_HEAD 0x04 +#define HEAD_WRAP_COUNT 0xFFE00000 +#define HEAD_WRAP_ONE 0x00200000 +#define HEAD_ADDR 0x001FFFFC +#define RING_START 0x08 +#define START_ADDR 0x00FFFFF8 +#define RING_LEN 0x0C +#define RING_NR_PAGES 0x000FF000 +#define RING_REPORT_MASK 0x00000006 +#define RING_REPORT_64K 0x00000002 +#define RING_REPORT_128K 0x00000004 +#define RING_NO_REPORT 0x00000000 +#define RING_VALID_MASK 0x00000001 +#define RING_VALID 0x00000001 +#define RING_INVALID 0x00000000 + +#define GFX_OP_SCISSOR ((0x3<<29)|(0x1c<<24)|(0x10<<19)) +#define SC_UPDATE_SCISSOR (0x1<<1) +#define SC_ENABLE_MASK (0x1<<0) +#define SC_ENABLE (0x1<<0) + +#define GFX_OP_SCISSOR_INFO ((0x3<<29)|(0x1d<<24)|(0x81<<16)|(0x1)) +#define SCI_YMIN_MASK (0xffff<<16) +#define SCI_XMIN_MASK (0xffff<<0) +#define SCI_YMAX_MASK (0xffff<<16) +#define SCI_XMAX_MASK (0xffff<<0) #endif + diff --git a/linux-core/mga_drv.c b/linux-core/mga_drv.c index 8bc25617e..480413549 100644 --- a/linux-core/mga_drv.c +++ b/linux-core/mga_drv.c @@ -54,6 +54,7 @@ static struct file_operations mga_fops = { mmap: drm_mmap, read: drm_read, fasync: drm_fasync, + poll: drm_poll, }; static struct miscdevice mga_misc = { @@ -105,9 +106,11 @@ static drm_ioctl_desc_t mga_ioctls[] = { [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = { drm_agp_bind, 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = { drm_agp_unbind, 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_MGA_INIT)] = { mga_dma_init, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_MGA_SWAP)] = { mga_clear_bufs, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_MGA_CLEAR)] = { mga_swap_bufs, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_MGA_ILOAD)] = { mga_iload, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_MGA_SWAP)] = { mga_swap_bufs, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_MGA_CLEAR)] = { mga_clear_bufs, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_MGA_ILOAD)] = { mga_iload, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_MGA_VERTEX)] = { mga_vertex, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_MGA_FLUSH)] = { mga_flush_ioctl, 1, 0 }, }; #define MGA_IOCTL_COUNT DRM_ARRAY_SIZE(mga_ioctls) @@ -380,6 +383,21 @@ int mga_init(void) drm_proc_init(dev); DRM_DEBUG("doing agp init\n"); dev->agp = drm_agp_init(); + if(dev->agp == NULL) { + DRM_DEBUG("The mga drm module requires the agpgart module" + " to function correctly\nPlease load the agpgart" + " module before you load the mga module\n"); + drm_proc_cleanup(); + misc_deregister(&mga_misc); + mga_takedown(dev); + return -ENOMEM; + } +#ifdef CONFIG_MTRR + dev->agp->agp_mtrr = mtrr_add(dev->agp->agp_info.aper_base, + dev->agp->agp_info.aper_size * 1024 * 1024, + MTRR_TYPE_WRCOMB, + 1); +#endif DRM_DEBUG("doing ctxbitmap init\n"); if((retcode = drm_ctxbitmap_init(dev))) { DRM_ERROR("Cannot allocate memory for context bitmap.\n"); @@ -416,6 +434,16 @@ void mga_cleanup(void) } drm_ctxbitmap_cleanup(dev); mga_dma_cleanup(dev); +#ifdef CONFIG_MTRR + if(dev->agp && dev->agp->agp_mtrr) { + int retval; + retval = mtrr_del(dev->agp->agp_mtrr, + dev->agp->agp_info.aper_base, + dev->agp->agp_info.aper_size * 1024*1024); + DRM_DEBUG("mtrr_del = %d\n", retval); + } +#endif + mga_takedown(dev); if (dev->agp) { drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS); diff --git a/linux-core/tdfx_drv.c b/linux-core/tdfx_drv.c index 57c1c719d..fb7a997b4 100644 --- a/linux-core/tdfx_drv.c +++ b/linux-core/tdfx_drv.c @@ -85,6 +85,16 @@ static drm_ioctl_desc_t tdfx_ioctls[] = { [DRM_IOCTL_NR(DRM_IOCTL_LOCK)] = { tdfx_lock, 1, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = { tdfx_unlock, 1, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { drm_finish, 1, 0 }, +#ifdef DRM_AGP + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)] = {drm_agp_acquire, 1, 1}, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)] = {drm_agp_release, 1, 1}, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)] = {drm_agp_enable, 1, 1}, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)] = {drm_agp_info, 1, 1}, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)] = {drm_agp_alloc, 1, 1}, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)] = {drm_agp_free, 1, 1}, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = {drm_agp_unbind, 1, 1}, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = {drm_agp_bind, 1, 1}, +#endif }; #define TDFX_IOCTL_COUNT DRM_ARRAY_SIZE(tdfx_ioctls) @@ -228,7 +238,24 @@ static int tdfx_takedown(drm_device_t *dev) } dev->magiclist[i].head = dev->magiclist[i].tail = NULL; } - +#ifdef DRM_AGP + /* Clear AGP information */ + if (dev->agp) { + drm_agp_mem_t *temp; + drm_agp_mem_t *temp_next; + + temp = dev->agp->memory; + while(temp != NULL) { + temp_next = temp->next; + drm_free_agp(temp->memory, temp->pages); + drm_free(temp, sizeof(*temp), DRM_MEM_AGPLISTS); + temp = temp_next; + } + if(dev->agp->acquired) (*drm_agp.release)(); + drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS); + dev->agp = NULL; + } +#endif /* Clear vma list (only built for debugging) */ if (dev->vmalist) { for (vma = dev->vmalist; vma; vma = vma_next) { @@ -262,6 +289,10 @@ static int tdfx_takedown(drm_device_t *dev) - PAGE_SHIFT, DRM_MEM_SAREA); break; + case _DRM_AGP: + /* Do nothing here, because this is all + handled in the AGP/GART driver. */ + break; } drm_free(map, sizeof(*map), DRM_MEM_MAPS); } @@ -309,6 +340,16 @@ int tdfx_init(void) drm_mem_init(); drm_proc_init(dev); +#ifdef DRM_AGP + dev->agp = drm_agp_init(); +#endif + if((retcode = drm_ctxbitmap_init(dev))) { + DRM_ERROR("Cannot allocate memory for context bitmap.\n"); + drm_proc_cleanup(); + misc_deregister(&tdfx_misc); + tdfx_takedown(dev); + return retcode; + } DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", TDFX_NAME, @@ -335,6 +376,7 @@ void tdfx_cleanup(void) } else { DRM_INFO("Module unloaded\n"); } + drm_ctxbitmap_cleanup(dev); tdfx_takedown(dev); } diff --git a/linux/Makefile.kernel b/linux/Makefile.kernel index 44d75c487..2ea6c7215 100644 --- a/linux/Makefile.kernel +++ b/linux/Makefile.kernel @@ -14,7 +14,8 @@ L_TARGET := libdrm.a L_OBJS := init.o memory.o proc.o auth.o context.o drawable.o bufs.o \ - lists.o lock.o ioctl.o fops.o vm.o dma.o + lists.o lock.o ioctl.o fops.o vm.o dma.o ctxbitmap.o \ + agpsupport.o M_OBJS := @@ -26,6 +27,14 @@ ifdef CONFIG_DRM_TDFX M_OBJS += tdfx.o endif +ifdef CONFIG_DRM_MGA +M_OBJS += mga.o +endif + +ifdef CONFIG_DRM_R128 +M_OBJS += r128.o +endif + include $(TOPDIR)/Rules.make gamma.o: gamma_drv.o gamma_dma.o $(L_TARGET) @@ -33,3 +42,10 @@ gamma.o: gamma_drv.o gamma_dma.o $(L_TARGET) tdfx.o: tdfx_drv.o tdfx_context.o $(L_TARGET) $(LD) $(LD_RFLAG) -r -o $@ tdfx_drv.o tdfx_context.o -L. -ldrm + +i810.o: i810_drv.o i810_context.o $(L_TARGET) + $(LD) $(LD_RFLAG) -r -o $@ i810_drv.o i810_bufs.o i810_dma.o i810_context.o -L. -ldrm + +mga.o: mga_drv.o mga_context.o mga_dma.o mga_bufs.o $(L_TARGET) + $(LD) $(LD_RFLAG) -r -o $@ mga_drv.o mga_bufs.o mga_dma.o mga_context.o mga_state.o -L. -ldrm + diff --git a/linux/Makefile.linux b/linux/Makefile.linux index 8a41f880b..1db7a81fa 100644 --- a/linux/Makefile.linux +++ b/linux/Makefile.linux @@ -31,12 +31,14 @@ # *** Setup +# **** End of SMP/MODVERSIONS detection + MODS= gamma.o tdfx.o LIBS= libdrm.a PROGS= drmstat DRMOBJS= init.o memory.o proc.o auth.o context.o drawable.o bufs.o \ - lists.o lock.o ioctl.o fops.o vm.o dma.o + lists.o lock.o ioctl.o fops.o vm.o dma.o ctxbitmap.o DRMHEADERS= drm.h drmP.h GAMMAOBJS= gamma_drv.o gamma_dma.o @@ -48,6 +50,8 @@ TDFXHEADERS= tdfx_drv.h $(DRMHEADERS) PROGOBJS= drmstat.po xf86drm.po xf86drmHash.po xf86drmRandom.po sigio.po PROGHEADERS= xf86drm.h $(DRMHEADERS) +INC= /usr/include + CFLAGS= -O2 $(WARNINGS) WARNINGS= -Wall -Wwrite-strings -Wpointer-arith -Wcast-align \ -Wstrict-prototypes -Wshadow -Wnested-externs \ @@ -102,7 +106,27 @@ SMP := $(shell gcc -E -nostdinc -I$(TREE) picker.c 2>/dev/null \ | grep -s 'SMP = ' | cut -d' ' -f3) MODVERSIONS := $(shell gcc -E -I $(TREE) picker.c 2>/dev/null \ | grep -s 'MODVERSIONS = ' | cut -d' ' -f3) -all::;@echo KERNEL HEADERS IN $(TREE): SMP=${SMP} MODVERSIONS=${MODVERSIONS} +AGP := $(shell gcc -E -nostdinc -I$(TREE) picker.c 2>/dev/null \ + | grep -s 'AGP = ' | cut -d' ' -f3) +ifeq ($(AGP),0) +AGP := $(shell gcc -E -nostdinc -I$(TREE) picker.c 2>/dev/null \ + | grep -s 'AGP_MODULE = ' | cut -d' ' -f3) +endif + +ifeq ($(AGP),1) +MODCFLAGS += -DDRM_AGP +DRMOBJS += agpsupport.o +MODS += mga.o i810.o + +MGAOBJS= mga_drv.o mga_dma.o mga_bufs.o mga_state.o mga_context.o +MGAHEADERS= mga_drv.h $(DRMHEADERS) + +I810OBJS= i810_drv.o i810_dma.o i810_bufs.o i810_context.o +I810HEADERS= i810_drv.h $(DRMHEADERS) +endif + +all::;@echo KERNEL HEADERS IN $(TREE): SMP=${SMP} MODVERSIONS=${MODVERSIONS} \ + AGP=${AGP} all:: $(LIBS) $(MODS) $(PROGS) endif @@ -116,6 +140,7 @@ ifeq ($(MODVERSIONS),1) MODCFLAGS += -DMODVERSIONS -include $(TREE)/linux/modversions.h endif + # **** End of configuration libdrm.a: $(DRMOBJS) @@ -128,6 +153,14 @@ gamma.o: $(GAMMAOBJS) $(LIBS) tdfx.o: $(TDFXOBJS) $(LIBS) $(LD) -r $^ -o $@ +ifeq ($(AGP),1) +mga.o: $(MGAOBJS) $(LIBS) + $(LD) -r $^ -o $@ + +i810.o: $(I810OBJS) $(LIBS) + $(LD) -r $^ -o $@ +endif + drmstat: $(PROGOBJS) $(CC) $(PRGCFLAGS) $^ $(PRGLIBS) -o $@ @@ -149,8 +182,11 @@ ChangeLog: $(DRMOBJS): $(DRMHEADERS) $(GAMMAOBJS): $(GAMMAHEADERS) $(TDFXOBJS): $(TDFXHEADERS) +ifeq ($(AGP),1) +$(MGAOBJS): $(MGAHEADERS) +$(I810OBJS): $(I810HEADERS) +endif $(PROGOBJS): $(PROGHEADERS) clean: - rm -f *.o *.po *~ core $(PROGS) - + rm -f *.o *.a *.po *~ core $(PROGS) diff --git a/linux/agpsupport.c b/linux/agpsupport.c index fb58154d6..c2da9ec7e 100644 --- a/linux/agpsupport.c +++ b/linux/agpsupport.c @@ -159,6 +159,8 @@ int drm_agp_alloc(struct inode *inode, struct file *filp, unsigned int cmd, -EFAULT); if (!(entry = drm_alloc(sizeof(*entry), DRM_MEM_AGPLISTS))) return -ENOMEM; + + memset(entry, 0, sizeof(*entry)); pages = (request.size + PAGE_SIZE - 1) / PAGE_SIZE; type = (u32) request.type; @@ -254,8 +256,10 @@ int drm_agp_free(struct inode *inode, struct file *filp, unsigned int cmd, if (!(entry = drm_agp_lookup_entry(dev, request.handle))) return -EINVAL; if (entry->bound) drm_unbind_agp(entry->memory); - entry->prev->next = entry->next; - entry->next->prev = entry->prev; + + if (entry->prev) entry->prev->next = entry->next; + else dev->agp->memory = entry->next; + if (entry->next) entry->next->prev = entry->prev; drm_free_agp(entry->memory, entry->pages); drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS); return 0; @@ -269,15 +273,12 @@ drm_agp_head_t *drm_agp_init(void) for (fill = &drm_agp_fill[0]; fill->name; fill++) { char *n = (char *)fill->name; -#if 0 - *fill->f = (drm_agp_func_u)get_module_symbol(NULL, n); -#endif *fill->f = (drm_agp_func_u)get_module_symbol(NULL, n); - printk("%s resolves to 0x%08lx\n", n, (*fill->f).address); + DRM_DEBUG("%s resolves to 0x%08lx\n", n, (*fill->f).address); if (!(*fill->f).address) agp_available = 0; } - printk("agp_available = %d\n", agp_available); + DRM_DEBUG("agp_available = %d\n", agp_available); if (agp_available) { if (!(head = drm_alloc(sizeof(*head), DRM_MEM_AGPLISTS))) diff --git a/linux/bufs.c b/linux/bufs.c index 85244c7dc..7902f0ccf 100644 --- a/linux/bufs.c +++ b/linux/bufs.c @@ -102,6 +102,11 @@ int drm_addmap(struct inode *inode, struct file *filp, unsigned int cmd, dev->lock.hw_lock = map->handle; /* Pointer to lock */ } break; +#ifdef DRM_AGP + case _DRM_AGP: + map->offset = map->offset + dev->agp->base; + break; +#endif default: drm_free(map, sizeof(*map), DRM_MEM_MAPS); return -EINVAL; @@ -172,7 +177,7 @@ int drm_addbufs(struct inode *inode, struct file *filp, unsigned int cmd, if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL; if (dev->queue_count) return -EBUSY; /* Not while in use */ - alignment = (request.flags & DRM_PAGE_ALIGN) ? PAGE_ALIGN(size) :size; + alignment = (request.flags & _DRM_PAGE_ALIGN) ? PAGE_ALIGN(size):size; page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; total = PAGE_SIZE << page_order; diff --git a/linux/ctxbitmap.c b/linux/ctxbitmap.c index f67209d44..781984f11 100644 --- a/linux/ctxbitmap.c +++ b/linux/ctxbitmap.c @@ -53,7 +53,7 @@ int drm_ctxbitmap_next(drm_device_t *dev) bit = find_first_zero_bit(dev->ctx_bitmap, DRM_MAX_CTXBITMAP); if (bit < DRM_MAX_CTXBITMAP) { set_bit(bit, dev->ctx_bitmap); - printk("drm_ctxbitmap_next bit : %d\n", bit); + DRM_DEBUG("drm_ctxbitmap_next bit : %d\n", bit); return bit; } return -1; @@ -64,15 +64,15 @@ int drm_ctxbitmap_init(drm_device_t *dev) int i; int temp; - dev->ctx_bitmap = (unsigned long *) drm_alloc(PAGE_SIZE * 4, + dev->ctx_bitmap = (unsigned long *) drm_alloc(PAGE_SIZE, DRM_MEM_CTXBITMAP); if(dev->ctx_bitmap == NULL) { return -ENOMEM; } - memset((void *) dev->ctx_bitmap, 0, PAGE_SIZE * 4); + memset((void *) dev->ctx_bitmap, 0, PAGE_SIZE); for(i = 0; i < DRM_RESERVED_CONTEXTS; i++) { temp = drm_ctxbitmap_next(dev); - printk("drm_ctxbitmap_init : %d\n", temp); + DRM_DEBUG("drm_ctxbitmap_init : %d\n", temp); } return 0; @@ -80,7 +80,7 @@ int drm_ctxbitmap_init(drm_device_t *dev) void drm_ctxbitmap_cleanup(drm_device_t *dev) { - drm_free((void *)dev->ctx_bitmap, PAGE_SIZE * 4, + drm_free((void *)dev->ctx_bitmap, PAGE_SIZE, DRM_MEM_CTXBITMAP); } diff --git a/linux/dma.c b/linux/dma.c index 8291e52e4..37ab674f8 100644 --- a/linux/dma.c +++ b/linux/dma.c @@ -63,15 +63,24 @@ void drm_dma_takedown(drm_device_t *dev) dma->bufs[i].page_order, DRM_MEM_DMA); } - drm_free(dma->bufs[i].buflist, - dma->buf_count - * sizeof(*dma->bufs[0].buflist), - DRM_MEM_BUFS); drm_free(dma->bufs[i].seglist, - dma->buf_count + dma->bufs[i].seg_count * sizeof(*dma->bufs[0].seglist), DRM_MEM_SEGS); - drm_freelist_destroy(&dma->bufs[i].freelist); + } + if(dma->bufs[i].buf_count) { + for(j = 0; j < dma->bufs[i].buf_count; j++) { + if(dma->bufs[i].buflist[j].dev_private) { + drm_free(dma->bufs[i].buflist[j].dev_private, + dma->bufs[i].buflist[j].dev_priv_size, + DRM_MEM_BUFS); + } + } + drm_free(dma->bufs[i].buflist, + dma->bufs[i].buf_count * + sizeof(*dma->bufs[0].buflist), + DRM_MEM_BUFS); + drm_freelist_destroy(&dma->bufs[i].freelist); } } diff --git a/linux/drm.h b/linux/drm.h index 7b8e88265..ae4c65ca3 100644 --- a/linux/drm.h +++ b/linux/drm.h @@ -61,6 +61,19 @@ typedef unsigned int drm_context_t; typedef unsigned int drm_drawable_t; typedef unsigned int drm_magic_t; +/* Warning: If you change this structure, make sure you change + * XF86DRIClipRectRec in the server as well */ + +typedef struct drm_clip_rect { + unsigned short x1; + unsigned short y1; + unsigned short x2; + unsigned short y2; +} drm_clip_rect_t; + +/* Seperate include files for the i810/mga specific structures */ +#include "mga_drm.h" +#include "i810_drm.h" typedef struct drm_version { int version_major; /* Major version */ @@ -101,7 +114,8 @@ typedef struct drm_control { typedef enum drm_map_type { _DRM_FRAME_BUFFER = 0, /* WC (no caching), no core dump */ _DRM_REGISTERS = 1, /* no caching, no core dump */ - _DRM_SHM = 2 /* shared, cached */ + _DRM_SHM = 2, /* shared, cached */ + _DRM_AGP = 3 /* AGP/GART */ } drm_map_type_t; typedef enum drm_map_flags { @@ -165,8 +179,11 @@ typedef struct drm_buf_desc { int low_mark; /* Low water mark */ int high_mark; /* High water mark */ enum { - DRM_PAGE_ALIGN = 0x01 /* Align on page boundaries for DMA */ + _DRM_PAGE_ALIGN = 0x01, /* Align on page boundaries for DMA */ + _DRM_AGP_BUFFER = 0x02 /* Buffer is in agp space */ } flags; + unsigned long agp_start; /* Start address of where the agp buffers + * are in the agp aperture */ } drm_buf_desc_t; typedef struct drm_buf_info { @@ -237,6 +254,38 @@ typedef struct drm_irq_busid { int funcnum; } drm_irq_busid_t; +typedef struct drm_agp_mode { + unsigned long mode; +} drm_agp_mode_t; + + /* For drm_agp_alloc -- allocated a buffer */ +typedef struct drm_agp_buffer { + unsigned long size; /* In bytes -- will round to page boundary */ + unsigned long handle; /* Used for BIND/UNBIND ioctls */ + unsigned long type; /* Type of memory to allocate */ + unsigned long physical; /* Physical used by i810 */ +} drm_agp_buffer_t; + + /* For drm_agp_bind */ +typedef struct drm_agp_binding { + unsigned long handle; /* From drm_agp_buffer */ + unsigned long offset; /* In bytes -- will round to page boundary */ +} drm_agp_binding_t; + +typedef struct drm_agp_info { + int agp_version_major; + int agp_version_minor; + unsigned long mode; + unsigned long aperture_base; /* physical address */ + unsigned long aperture_size; /* bytes */ + unsigned long memory_allowed; /* bytes */ + unsigned long memory_used; + + /* PCI information */ + unsigned short id_vendor; + unsigned short id_device; +} drm_agp_info_t; + #define DRM_IOCTL_BASE 'd' #define DRM_IOCTL_NR(n) _IOC_NR(n) #define DRM_IO(nr) _IO(DRM_IOCTL_BASE,nr) @@ -276,4 +325,28 @@ typedef struct drm_irq_busid { #define DRM_IOCTL_UNLOCK DRM_IOW( 0x2b, drm_lock_t) #define DRM_IOCTL_FINISH DRM_IOW( 0x2c, drm_lock_t) +#define DRM_IOCTL_AGP_ACQUIRE DRM_IO( 0x30) +#define DRM_IOCTL_AGP_RELEASE DRM_IO( 0x31) +#define DRM_IOCTL_AGP_ENABLE DRM_IOR( 0x32, drm_agp_mode_t) +#define DRM_IOCTL_AGP_INFO DRM_IOW( 0x33, drm_agp_info_t) +#define DRM_IOCTL_AGP_ALLOC DRM_IOWR(0x34, drm_agp_buffer_t) +#define DRM_IOCTL_AGP_FREE DRM_IOW( 0x35, drm_agp_buffer_t) +#define DRM_IOCTL_AGP_BIND DRM_IOWR(0x36, drm_agp_binding_t) +#define DRM_IOCTL_AGP_UNBIND DRM_IOW( 0x37, drm_agp_binding_t) + +/* Mga specific ioctls */ +#define DRM_IOCTL_MGA_INIT DRM_IOW( 0x40, drm_mga_init_t) +#define DRM_IOCTL_MGA_SWAP DRM_IOW( 0x41, drm_mga_swap_t) +#define DRM_IOCTL_MGA_CLEAR DRM_IOW( 0x42, drm_mga_clear_t) +#define DRM_IOCTL_MGA_ILOAD DRM_IOW( 0x43, drm_mga_iload_t) +#define DRM_IOCTL_MGA_VERTEX DRM_IOW( 0x44, drm_mga_vertex_t) +#define DRM_IOCTL_MGA_FLUSH DRM_IOW( 0x45, drm_lock_t ) + +/* I810 specific ioctls */ +#define DRM_IOCTL_I810_INIT DRM_IOW( 0x40, drm_i810_init_t) +#define DRM_IOCTL_I810_VERTEX DRM_IOW( 0x41, drm_i810_vertex_t) +#define DRM_IOCTL_I810_DMA DRM_IOW( 0x42, drm_i810_general_t) +#define DRM_IOCTL_I810_FLUSH DRM_IO ( 0x43) +#define DRM_IOCTL_I810_GETAGE DRM_IO ( 0x44) + #endif diff --git a/linux/drmP.h b/linux/drmP.h index 312fba36f..f8e78eabd 100644 --- a/linux/drmP.h +++ b/linux/drmP.h @@ -48,8 +48,12 @@ #ifdef CONFIG_MTRR #include #endif +#ifdef DRM_AGP +#include +#include +#endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) -#include +#include #include #endif #include "drm.h" @@ -69,21 +73,27 @@ #define DRM_FLAG_DEBUG 0x01 #define DRM_FLAG_NOCTX 0x02 -#define DRM_MEM_DMA 0 -#define DRM_MEM_SAREA 1 -#define DRM_MEM_DRIVER 2 -#define DRM_MEM_MAGIC 3 -#define DRM_MEM_IOCTLS 4 -#define DRM_MEM_MAPS 5 -#define DRM_MEM_VMAS 6 -#define DRM_MEM_BUFS 7 -#define DRM_MEM_SEGS 8 -#define DRM_MEM_PAGES 9 -#define DRM_MEM_FILES 10 -#define DRM_MEM_QUEUES 11 -#define DRM_MEM_CMDS 12 -#define DRM_MEM_MAPPINGS 13 -#define DRM_MEM_BUFLISTS 14 +#define DRM_MEM_DMA 0 +#define DRM_MEM_SAREA 1 +#define DRM_MEM_DRIVER 2 +#define DRM_MEM_MAGIC 3 +#define DRM_MEM_IOCTLS 4 +#define DRM_MEM_MAPS 5 +#define DRM_MEM_VMAS 6 +#define DRM_MEM_BUFS 7 +#define DRM_MEM_SEGS 8 +#define DRM_MEM_PAGES 9 +#define DRM_MEM_FILES 10 +#define DRM_MEM_QUEUES 11 +#define DRM_MEM_CMDS 12 +#define DRM_MEM_MAPPINGS 13 +#define DRM_MEM_BUFLISTS 14 +#define DRM_MEM_AGPLISTS 15 +#define DRM_MEM_TOTALAGP 16 +#define DRM_MEM_BOUNDAGP 17 +#define DRM_MEM_CTXBITMAP 18 + +#define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8) /* Backward compatibility section */ /* _PAGE_WT changed to _PAGE_PWT in 2.2.6 */ @@ -235,6 +245,7 @@ typedef struct drm_buf { int used; /* Amount of buffer in use (for DMA) */ unsigned long offset; /* Byte offset (used internally) */ void *address; /* Address of buffer */ + unsigned long bus_address; /* Bus address of buffer */ struct drm_buf *next; /* Kernel-only: used for free list */ __volatile__ int waiting; /* On kernel DMA queue */ __volatile__ int pending; /* On hardware DMA queue */ @@ -250,6 +261,11 @@ typedef struct drm_buf { DRM_LIST_PRIO = 4, DRM_LIST_RECLAIM = 5 } list; /* Which list we're on */ + + + void *dev_private; + int dev_priv_size; + #if DRM_DMA_HISTOGRAM cycles_t time_queued; /* Queued to kernel DMA queue */ cycles_t time_dispatched; /* Dispatched to hardware */ @@ -376,6 +392,9 @@ typedef struct drm_device_dma { int page_count; unsigned long *pagelist; unsigned long byte_count; + enum { + _DRM_DMA_USE_AGP = 0x01 + } flags; /* DMA support */ drm_buf_t *this_buffer; /* Buffer being sent */ @@ -384,6 +403,41 @@ typedef struct drm_device_dma { wait_queue_head_t waiting; /* Processes waiting on free bufs */ } drm_device_dma_t; +#ifdef DRM_AGP +typedef struct drm_agp_mem { + unsigned long handle; + agp_memory *memory; + unsigned long bound; /* address */ + int pages; + struct drm_agp_mem *prev; + struct drm_agp_mem *next; +} drm_agp_mem_t; + +typedef struct drm_agp_head { + agp_kern_info agp_info; + const char *chipset; + drm_agp_mem_t *memory; + unsigned long mode; + int enabled; + int acquired; + unsigned long base; + int agp_mtrr; +} drm_agp_head_t; + +typedef struct { + void (*free_memory)(agp_memory *); + agp_memory *(*allocate_memory)(size_t, u32); + int (*bind_memory)(agp_memory *, off_t); + int (*unbind_memory)(agp_memory *); + void (*enable)(u32); + int (*acquire)(void); + void (*release)(void); + void (*copy_info)(agp_kern_info *); +} drm_agp_func_t; + +extern drm_agp_func_t drm_agp; +#endif + typedef struct drm_device { const char *name; /* Simple driver name */ char *unique; /* Unique identifier: e.g., busid */ @@ -462,6 +516,12 @@ typedef struct drm_device { struct fasync_struct *buf_async;/* Processes waiting for SIGIO */ wait_queue_head_t buf_readers; /* Processes waiting to read */ wait_queue_head_t buf_writers; /* Processes waiting to ctx switch */ + +#ifdef DRM_AGP + drm_agp_head_t *agp; +#endif + unsigned long *ctx_bitmap; + void *dev_private; } drm_device_t; @@ -533,6 +593,14 @@ extern void drm_free_pages(unsigned long address, int order, extern void *drm_ioremap(unsigned long offset, unsigned long size); extern void drm_ioremapfree(void *pt, unsigned long size); +#ifdef DRM_AGP +extern agp_memory *drm_alloc_agp(int pages, u32 type); +extern int drm_free_agp(agp_memory *handle, int pages); +extern int drm_bind_agp(agp_memory *handle, unsigned int start); +extern int drm_unbind_agp(agp_memory *handle); +#endif + + /* Buffer management support (bufs.c) */ extern int drm_order(unsigned long size); extern int drm_addmap(struct inode *inode, struct file *filp, @@ -642,5 +710,32 @@ extern int drm_flush_unblock(drm_device_t *dev, int context, drm_lock_flags_t flags); extern int drm_flush_block_and_flush(drm_device_t *dev, int context, drm_lock_flags_t flags); + + /* Context Bitmap support (ctxbitmap.c) */ +extern int drm_ctxbitmap_init(drm_device_t *dev); +extern void drm_ctxbitmap_cleanup(drm_device_t *dev); +extern int drm_ctxbitmap_next(drm_device_t *dev); +extern void drm_ctxbitmap_free(drm_device_t *dev, int ctx_handle); + +#ifdef DRM_AGP + /* AGP/GART support (agpsupport.c) */ +extern drm_agp_head_t *drm_agp_init(void); +extern int drm_agp_acquire(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_agp_release(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_agp_enable(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_agp_info(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_agp_alloc(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_agp_free(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_agp_unbind(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_agp_bind(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +#endif #endif #endif diff --git a/linux/gamma_drv.c b/linux/gamma_drv.c index ce970835a..a3c2bd4a0 100644 --- a/linux/gamma_drv.c +++ b/linux/gamma_drv.c @@ -271,6 +271,10 @@ static int gamma_takedown(drm_device_t *dev) - PAGE_SHIFT, DRM_MEM_SAREA); break; + case _DRM_AGP: + /* Do nothing here, because this is all + handled in the AGP/GART driver. */ + break; } drm_free(map, sizeof(*map), DRM_MEM_MAPS); } diff --git a/linux/i810_bufs.c b/linux/i810_bufs.c index 49455b434..c025e400b 100644 --- a/linux/i810_bufs.c +++ b/linux/i810_bufs.c @@ -32,152 +32,28 @@ #define __NO_VERSION__ #include "drmP.h" +#include "i810_drv.h" #include "linux/un.h" int i810_addbufs_agp(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_device_dma_t *dma = dev->dma; - drm_buf_desc_t request; - drm_buf_entry_t *entry; - drm_buf_t *buf; - unsigned long offset; - unsigned long agp_offset; - int count; - int order; - int size; - int alignment; - int page_order; - int total; - int byte_count; - int i; - - if (!dma) return -EINVAL; - - copy_from_user_ret(&request, - (drm_buf_desc_t *)arg, - sizeof(request), - -EFAULT); - - count = request.count; - order = drm_order(request.size); - size = 1 << order; - agp_offset = request.agp_start; - alignment = (request.flags & _DRM_PAGE_ALIGN) ? PAGE_ALIGN(size) :size; - page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; - total = PAGE_SIZE << page_order; - byte_count = 0; - - if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL; - if (dev->queue_count) return -EBUSY; /* Not while in use */ - spin_lock(&dev->count_lock); - if (dev->buf_use) { - spin_unlock(&dev->count_lock); - return -EBUSY; - } - atomic_inc(&dev->buf_alloc); - spin_unlock(&dev->count_lock); - - down(&dev->struct_sem); - entry = &dma->bufs[order]; - if (entry->buf_count) { - up(&dev->struct_sem); - 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) { - up(&dev->struct_sem); - atomic_dec(&dev->buf_alloc); - return -ENOMEM; - } - memset(entry->buflist, 0, count * sizeof(*entry->buflist)); - - entry->buf_size = size; - entry->page_order = page_order; - - while(entry->buf_count < count) { - for(offset = 0; offset + size <= total && entry->buf_count < count; - offset += alignment, ++entry->buf_count) { - buf = &entry->buflist[entry->buf_count]; - buf->idx = dma->buf_count + entry->buf_count; - buf->total = alignment; - buf->order = order; - buf->used = 0; - buf->offset = agp_offset - dev->agp->base + offset;/* ?? */ - buf->bus_address = agp_offset + offset; - buf->address = agp_offset + offset + dev->agp->base; - buf->next = NULL; - buf->waiting = 0; - buf->pending = 0; - init_waitqueue_head(&buf->dma_wait); - buf->pid = 0; -#if DRM_DMA_HISTOGRAM - buf->time_queued = 0; - buf->time_dispatched = 0; - buf->time_completed = 0; - buf->time_freed = 0; -#endif - DRM_DEBUG("buffer %d @ %p\n", - entry->buf_count, buf->address); - } - byte_count += PAGE_SIZE << page_order; - } - - dma->buflist = drm_realloc(dma->buflist, - dma->buf_count * sizeof(*dma->buflist), - (dma->buf_count + entry->buf_count) - * sizeof(*dma->buflist), - DRM_MEM_BUFS); - for (i = dma->buf_count; i < dma->buf_count + entry->buf_count; i++) - dma->buflist[i] = &entry->buflist[i - dma->buf_count]; - - dma->buf_count += entry->buf_count; - dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order); - - drm_freelist_create(&entry->freelist, entry->buf_count); - for (i = 0; i < entry->buf_count; i++) { - drm_freelist_put(dev, &entry->freelist, &entry->buflist[i]); - } - - up(&dev->struct_sem); - - request.count = entry->buf_count; - request.size = size; - - copy_to_user_ret((drm_buf_desc_t *)arg, - &request, - sizeof(request), - -EFAULT); - - atomic_dec(&dev->buf_alloc); - return 0; -} - -int i810_addbufs_pci(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_device_dma_t *dma = dev->dma; - drm_buf_desc_t request; - int count; - int order; - int size; - int total; - int page_order; - drm_buf_entry_t *entry; - unsigned long page; - drm_buf_t *buf; - int alignment; - unsigned long offset; - int i; - int byte_count; - int page_count; + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_device_dma_t *dma = dev->dma; + drm_buf_desc_t request; + drm_buf_entry_t *entry; + drm_buf_t *buf; + unsigned long offset; + unsigned long agp_offset; + int count; + int order; + int size; + int alignment; + int page_order; + int total; + int byte_count; + int i; if (!dma) return -EINVAL; @@ -186,20 +62,17 @@ int i810_addbufs_pci(struct inode *inode, struct file *filp, unsigned int cmd, sizeof(request), -EFAULT); - count = request.count; - order = drm_order(request.size); - size = 1 << order; - - DRM_DEBUG("count = %d, size = %d (%d), order = %d, queue_count = %d\n", - request.count, request.size, size, order, dev->queue_count); - - if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL; - if (dev->queue_count) return -EBUSY; /* Not while in use */ - + count = request.count; + order = drm_order(request.size); + size = 1 << order; + agp_offset = request.agp_start; alignment = (request.flags & _DRM_PAGE_ALIGN) ? PAGE_ALIGN(size) :size; page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; - total = PAGE_SIZE << page_order; - + total = PAGE_SIZE << page_order; + byte_count = 0; + + if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL; + if (dev->queue_count) return -EBUSY; /* Not while in use */ spin_lock(&dev->count_lock); if (dev->buf_use) { spin_unlock(&dev->count_lock); @@ -207,15 +80,15 @@ int i810_addbufs_pci(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) { up(&dev->struct_sem); atomic_dec(&dev->buf_alloc); - return -ENOMEM; /* May only call once for each order */ + return -ENOMEM; /* May only call once for each order */ } - + entry->buflist = drm_alloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS); if (!entry->buflist) { @@ -224,69 +97,44 @@ int i810_addbufs_pci(struct inode *inode, struct file *filp, unsigned int cmd, return -ENOMEM; } memset(entry->buflist, 0, count * sizeof(*entry->buflist)); - - entry->seglist = drm_alloc(count * sizeof(*entry->seglist), - DRM_MEM_SEGS); - if (!entry->seglist) { - drm_free(entry->buflist, - count * sizeof(*entry->buflist), - DRM_MEM_BUFS); - up(&dev->struct_sem); - atomic_dec(&dev->buf_alloc); - return -ENOMEM; - } - memset(entry->seglist, 0, count * sizeof(*entry->seglist)); - - dma->pagelist = drm_realloc(dma->pagelist, - dma->page_count * sizeof(*dma->pagelist), - (dma->page_count + (count << page_order)) - * sizeof(*dma->pagelist), - DRM_MEM_PAGES); - DRM_DEBUG("pagelist: %d entries\n", - dma->page_count + (count << page_order)); - - - entry->buf_size = size; + + entry->buf_size = size; entry->page_order = page_order; - byte_count = 0; - page_count = 0; - while (entry->buf_count < count) { - if (!(page = drm_alloc_pages(page_order, DRM_MEM_DMA))) break; - entry->seglist[entry->seg_count++] = page; - for (i = 0; i < (1 << page_order); i++) { - DRM_DEBUG("page %d @ 0x%08lx\n", - dma->page_count + page_count, - page + PAGE_SIZE * i); - dma->pagelist[dma->page_count + page_count++] - = page + PAGE_SIZE * i; - } - for (offset = 0; - offset + size <= total && entry->buf_count < count; - offset += alignment, ++entry->buf_count) { - buf = &entry->buflist[entry->buf_count]; - buf->idx = dma->buf_count + entry->buf_count; - buf->total = alignment; - buf->order = order; - buf->used = 0; - buf->offset = (dma->byte_count + byte_count + offset); - buf->address = (void *)(page + offset); - buf->next = NULL; - buf->waiting = 0; - buf->pending = 0; - init_waitqueue_head(&buf->dma_wait); - buf->pid = 0; + offset = 0; + + while(entry->buf_count < count) { + buf = &entry->buflist[entry->buf_count]; + buf->idx = dma->buf_count + entry->buf_count; + buf->total = alignment; + buf->order = order; + buf->used = 0; + buf->offset = offset; + buf->bus_address = dev->agp->base + agp_offset + offset; + buf->address = (void *)(agp_offset + offset + dev->agp->base); + buf->next = NULL; + buf->waiting = 0; + buf->pending = 0; + init_waitqueue_head(&buf->dma_wait); + buf->pid = 0; + + buf->dev_private = drm_alloc(sizeof(drm_i810_buf_priv_t), + DRM_MEM_BUFS); + buf->dev_priv_size = sizeof(drm_i810_buf_priv_t); + #if DRM_DMA_HISTOGRAM - buf->time_queued = 0; - buf->time_dispatched = 0; - buf->time_completed = 0; - buf->time_freed = 0; + buf->time_queued = 0; + buf->time_dispatched = 0; + buf->time_completed = 0; + buf->time_freed = 0; #endif - DRM_DEBUG("buffer %d @ %p\n", - entry->buf_count, buf->address); - } + offset = offset + alignment; + entry->buf_count++; byte_count += PAGE_SIZE << page_order; + + DRM_DEBUG("buffer %d @ %p\n", + entry->buf_count, buf->address); } - + dma->buflist = drm_realloc(dma->buflist, dma->buf_count * sizeof(*dma->buflist), (dma->buf_count + entry->buf_count) @@ -294,45 +142,43 @@ int i810_addbufs_pci(struct inode *inode, struct file *filp, unsigned int cmd, DRM_MEM_BUFS); for (i = dma->buf_count; i < dma->buf_count + entry->buf_count; i++) dma->buflist[i] = &entry->buflist[i - dma->buf_count]; - - dma->buf_count += entry->buf_count; - dma->seg_count += entry->seg_count; - dma->page_count += entry->seg_count << page_order; - dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order); - + + dma->buf_count += entry->buf_count; + dma->byte_count += byte_count; drm_freelist_create(&entry->freelist, entry->buf_count); for (i = 0; i < entry->buf_count; i++) { drm_freelist_put(dev, &entry->freelist, &entry->buflist[i]); } - + up(&dev->struct_sem); - + request.count = entry->buf_count; request.size = size; - + copy_to_user_ret((drm_buf_desc_t *)arg, &request, sizeof(request), -EFAULT); - + atomic_dec(&dev->buf_alloc); + dma->flags = _DRM_DMA_USE_AGP; return 0; } int i810_addbufs(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { - drm_buf_desc_t request; + drm_buf_desc_t request; - copy_from_user_ret(&request, - (drm_buf_desc_t *)arg, - sizeof(request), - -EFAULT); + copy_from_user_ret(&request, + (drm_buf_desc_t *)arg, + sizeof(request), + -EFAULT); - if(request.flags & _DRM_AGP_BUFFER) - return i810_addbufs_agp(inode, filp, cmd, arg); - else - return i810_addbufs_pci(inode, filp, cmd, arg); + if(request.flags & _DRM_AGP_BUFFER) + return i810_addbufs_agp(inode, filp, cmd, arg); + else + return -EINVAL; } int i810_infobufs(struct inode *inode, struct file *filp, unsigned int cmd, @@ -487,7 +333,7 @@ int i810_freebufs(struct inode *inode, struct file *filp, unsigned int cmd, } int i810_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) + unsigned long arg) { drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; @@ -506,6 +352,7 @@ int i810_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd, spin_lock(&dev->count_lock); if (atomic_read(&dev->buf_alloc)) { spin_unlock(&dev->count_lock); + DRM_DEBUG("Busy\n"); return -EBUSY; } ++dev->buf_use; /* Can't allocate more after this call */ @@ -515,34 +362,46 @@ int i810_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd, (drm_buf_map_t *)arg, sizeof(request), -EFAULT); - - if (request.count >= dma->buf_count) { - if(dma->flags & _DRM_DMA_USE_AGP) { - /* This is an ugly vicious hack */ - drm_map_t *map = NULL; - for(i = 0; i < dev->map_count; i++) { - map = dev->maplist[i]; - if(map->type == _DRM_AGP) break; - } - if (i >= dev->map_count || !map) { - retcode = -EINVAL; - goto done; - } + DRM_DEBUG("dma->flags : %lx\n", dma->flags); + if (request.count >= dma->buf_count) { + if(dma->flags & _DRM_DMA_USE_AGP) { + drm_i810_private_t *dev_priv = + (drm_i810_private_t *)dev->dev_private; + drm_map_t *map = NULL; - virtual = do_mmap(filp, 0, map->size, PROT_READ|PROT_WRITE, - MAP_SHARED, (unsigned long)map->handle); - } - else { - virtual = do_mmap(filp, 0, dma->byte_count, - PROT_READ|PROT_WRITE, MAP_SHARED, 0); - } + map = dev->maplist[dev_priv->buffer_map_idx]; + if (!map) { + DRM_DEBUG("map is null\n"); + retcode = -EINVAL; + goto done; + } + DRM_DEBUG("map->offset : %lx\n", map->offset); + DRM_DEBUG("map->size : %lx\n", map->size); + DRM_DEBUG("map->type : %d\n", map->type); + DRM_DEBUG("map->flags : %x\n", map->flags); + DRM_DEBUG("map->handle : %lx\n", map->handle); + DRM_DEBUG("map->mtrr : %d\n", map->mtrr); + down(¤t->mm->mmap_sem); + virtual = do_mmap(filp, 0, map->size, + PROT_READ|PROT_WRITE, + MAP_SHARED, + (unsigned long)map->offset); + + up(¤t->mm->mmap_sem); + } else { + down(¤t->mm->mmap_sem); + virtual = do_mmap(filp, 0, dma->byte_count, + PROT_READ|PROT_WRITE, MAP_SHARED, 0); + up(¤t->mm->mmap_sem); + } if (virtual > -1024UL) { - /* Real error */ + /* Real error */ + DRM_DEBUG("mmap error\n"); retcode = (signed long)virtual; goto done; } request.virtual = (void *)virtual; - + for (i = 0; i < dma->buf_count; i++) { if (copy_to_user(&request.list[i].idx, &dma->buflist[i]->idx, @@ -571,14 +430,15 @@ int i810_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd, } } } -done: + done: request.count = dma->buf_count; DRM_DEBUG("%d buffers, retcode = %d\n", request.count, retcode); - + copy_to_user_ret((drm_buf_map_t *)arg, &request, sizeof(request), -EFAULT); + DRM_DEBUG("retcode : %d\n", retcode); return retcode; } diff --git a/linux/i810_context.c b/linux/i810_context.c new file mode 100644 index 000000000..5503edf24 --- /dev/null +++ b/linux/i810_context.c @@ -0,0 +1,205 @@ +/* i810_context.c -- IOCTLs for i810 contexts -*- linux-c -*- + * Created: Mon Dec 13 09:51:35 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * 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. + * + * Author: Rickard E. (Rik) Faith + * + * $XFree86$ + * + */ + +#include + +#define __NO_VERSION__ +#include "drmP.h" +#include "i810_drv.h" + +static int i810_alloc_queue(drm_device_t *dev) +{ + int temp = drm_ctxbitmap_next(dev); + DRM_DEBUG("i810_alloc_queue: %d\n", temp); + return temp; +} + +int i810_context_switch(drm_device_t *dev, int old, int new) +{ + char buf[64]; + + atomic_inc(&dev->total_ctx); + + if (test_and_set_bit(0, &dev->context_flag)) { + DRM_ERROR("Reentering -- FIXME\n"); + return -EBUSY; + } + +#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) { + i810_context_switch_complete(dev, new); + } else { + sprintf(buf, "C %d %d\n", old, new); + drm_write_string(dev, buf); + } + + return 0; +} + +int i810_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"); + } + + /* If a context switch is ever initiated + when the kernel holds the lock, release + that lock here. */ +#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; +} + +int i810_resctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_ctx_res_t res; + drm_ctx_t ctx; + int i; + + DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS); + copy_from_user_ret(&res, (drm_ctx_res_t *)arg, sizeof(res), -EFAULT); + if (res.count >= DRM_RESERVED_CONTEXTS) { + memset(&ctx, 0, sizeof(ctx)); + for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) { + ctx.handle = i; + copy_to_user_ret(&res.contexts[i], + &i, + sizeof(i), + -EFAULT); + } + } + res.count = DRM_RESERVED_CONTEXTS; + copy_to_user_ret((drm_ctx_res_t *)arg, &res, sizeof(res), -EFAULT); + return 0; +} + +int i810_addctx(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_ctx_t ctx; + + copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + if ((ctx.handle = i810_alloc_queue(dev)) == DRM_KERNEL_CONTEXT) { + /* Skip kernel's context and get a new one. */ + ctx.handle = i810_alloc_queue(dev); + } + if (ctx.handle == -1) { + DRM_DEBUG("Not enough free contexts.\n"); + /* Should this return -EBUSY instead? */ + return -ENOMEM; + } + DRM_DEBUG("%d\n", ctx.handle); + copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT); + return 0; +} + +int i810_modctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + /* This does nothing for the i810 */ + return 0; +} + +int i810_getctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_ctx_t ctx; + + copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT); + /* This is 0, because we don't hanlde any context flags */ + ctx.flags = 0; + copy_to_user_ret((drm_ctx_t*)arg, &ctx, sizeof(ctx), -EFAULT); + return 0; +} + +int i810_switchctx(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_ctx_t ctx; + + copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + DRM_DEBUG("%d\n", ctx.handle); + return i810_context_switch(dev, dev->last_context, ctx.handle); +} + +int i810_newctx(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_ctx_t ctx; + + copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + DRM_DEBUG("%d\n", ctx.handle); + i810_context_switch_complete(dev, ctx.handle); + + return 0; +} + +int i810_rmctx(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_ctx_t ctx; + + copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + DRM_DEBUG("%d\n", ctx.handle); + if(ctx.handle != DRM_KERNEL_CONTEXT) { + drm_ctxbitmap_free(dev, ctx.handle); + } + + return 0; +} diff --git a/linux/i810_dma.c b/linux/i810_dma.c index 09959b657..30fda5b8b 100644 --- a/linux/i810_dma.c +++ b/linux/i810_dma.c @@ -25,8 +25,9 @@ * * Authors: Rickard E. (Rik) Faith * Jeff Hartmann + * Keith Whitwell * - * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/i810_dma.c,v 1.1 2000/02/11 17:26:04 dawes Exp $ + * $XFree86$ * */ @@ -36,6 +37,9 @@ #include /* For task queue support */ +#define I810_BUF_FREE 1 +#define I810_BUF_USED 0 + #define I810_REG(reg) 2 #define I810_BASE(reg) ((unsigned long) \ dev->maplist[I810_REG(reg)]->handle) @@ -43,544 +47,457 @@ #define I810_DEREF(reg) *(__volatile__ int *)I810_ADDR(reg) #define I810_READ(reg) I810_DEREF(reg) #define I810_WRITE(reg,val) do { I810_DEREF(reg) = val; } while (0) - -void i810_dma_init(drm_device_t *dev) +#define I810_DEREF16(reg) *(__volatile__ u16 *)I810_ADDR(reg) +#define I810_READ16(reg) I810_DEREF16(reg) +#define I810_WRITE16(reg,val) do { I810_DEREF16(reg) = val; } while (0) + +#define RING_LOCALS unsigned int outring, ringmask; volatile char *virt; + +#define BEGIN_LP_RING(n) do { \ + if (I810_VERBOSE) \ + DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n", \ + n, __FUNCTION__); \ + if (dev_priv->ring.space < n*4) \ + i810_wait_ring(dev, n*4); \ + dev_priv->ring.space -= n*4; \ + outring = dev_priv->ring.tail; \ + ringmask = dev_priv->ring.tail_mask; \ + virt = dev_priv->ring.virtual_start; \ +} while (0) + +#define ADVANCE_LP_RING() do { \ + if (I810_VERBOSE) DRM_DEBUG("ADVANCE_LP_RING\n"); \ + dev_priv->ring.tail = outring; \ + I810_WRITE(LP_RING + RING_TAIL, outring); \ +} while(0) + +#define OUT_RING(n) do { \ + if (I810_VERBOSE) DRM_DEBUG(" OUT_RING %x\n", (int)(n)); \ + *(volatile unsigned int *)(virt + outring) = n; \ + outring += 4; \ + outring &= ringmask; \ +} while (0); + +static inline void i810_print_status_page(drm_device_t *dev) { - printk(KERN_INFO "i810_dma_init\n"); + drm_device_dma_t *dma = dev->dma; + drm_i810_private_t *dev_priv = dev->dev_private; + u32 *temp = (u32 *)dev_priv->hw_status_page; + int i; + + DRM_DEBUG( "hw_status: Interrupt Status : %x\n", temp[0]); + DRM_DEBUG( "hw_status: LpRing Head ptr : %x\n", temp[1]); + DRM_DEBUG( "hw_status: IRing Head ptr : %x\n", temp[2]); + DRM_DEBUG( "hw_status: Reserved : %x\n", temp[3]); + DRM_DEBUG( "hw_status: Driver Counter : %d\n", temp[5]); + for(i = 6; i < dma->buf_count + 6; i++) { + DRM_DEBUG( "buffer status idx : %d used: %d\n", i - 6, temp[i]); + } } -void i810_dma_cleanup(drm_device_t *dev) +static drm_buf_t *i810_freelist_get(drm_device_t *dev) { - printk(KERN_INFO "i810_dma_cleanup\n"); + drm_device_dma_t *dma = dev->dma; + int i; + int used; + + /* Linear search might not be the best solution */ + + for (i = 0; i < dma->buf_count; i++) { + drm_buf_t *buf = dma->buflist[ i ]; + drm_i810_buf_priv_t *buf_priv = buf->dev_private; + /* In use is already a pointer */ + used = cmpxchg(buf_priv->in_use, I810_BUF_FREE, + I810_BUF_USED); + if(used == I810_BUF_FREE) { + return buf; + } + } + return NULL; } -static inline void i810_dma_dispatch(drm_device_t *dev, unsigned long address, - unsigned long length) +/* This should only be called if the buffer is not sent to the hardware + * yet, the hardware updates in use for us once its on the ring buffer. + */ + +static int i810_freelist_put(drm_device_t *dev, drm_buf_t *buf) { - printk(KERN_INFO "i810_dma_dispatch\n"); + drm_i810_buf_priv_t *buf_priv = buf->dev_private; + int used; + + /* In use is already a pointer */ + used = cmpxchg(buf_priv->in_use, I810_BUF_USED, I810_BUF_FREE); + if(used != I810_BUF_USED) { + DRM_ERROR("Freeing buffer thats not in use : %d\n", buf->idx); + return -EINVAL; + } + + return 0; } -static inline void i810_dma_quiescent(drm_device_t *dev) +static int i810_dma_get_buffers(drm_device_t *dev, drm_dma_t *d) { + int i; + drm_buf_t *buf; + + for (i = d->granted_count; i < d->request_count; i++) { + buf = i810_freelist_get(dev); + if (!buf) break; + buf->pid = current->pid; + copy_to_user_ret(&d->request_indices[i], + &buf->idx, + sizeof(buf->idx), + -EFAULT); + copy_to_user_ret(&d->request_sizes[i], + &buf->total, + sizeof(buf->total), + -EFAULT); + ++d->granted_count; + } + return 0; } -static inline void i810_dma_ready(drm_device_t *dev) +static unsigned long i810_alloc_page(drm_device_t *dev) { - i810_dma_quiescent(dev); - printk(KERN_INFO "i810_dma_ready\n"); + unsigned long address; + + address = __get_free_page(GFP_KERNEL); + if(address == 0UL) + return 0; + + atomic_inc(&mem_map[MAP_NR((void *) address)].count); + set_bit(PG_locked, &mem_map[MAP_NR((void *) address)].flags); + + return address; } -static inline int i810_dma_is_ready(drm_device_t *dev) +static void i810_free_page(drm_device_t *dev, unsigned long page) { - - i810_dma_quiescent(dev); - - printk(KERN_INFO "i810_dma_is_ready\n"); - return 1; + if(page == 0UL) + return; + + atomic_dec(&mem_map[MAP_NR((void *) page)].count); + clear_bit(PG_locked, &mem_map[MAP_NR((void *) page)].flags); + wake_up(&mem_map[MAP_NR((void *) page)].wait); + free_page(page); + return; } - -static void i810_dma_service(int irq, void *device, struct pt_regs *regs) +static int i810_dma_cleanup(drm_device_t *dev) { - drm_device_t *dev = (drm_device_t *)device; - drm_device_dma_t *dma = dev->dma; - - atomic_inc(&dev->total_irq); - if (i810_dma_is_ready(dev)) { - /* Free previous buffer */ - if (test_and_set_bit(0, &dev->dma_flag)) { - atomic_inc(&dma->total_missed_free); - return; + if(dev->dev_private) { + drm_i810_private_t *dev_priv = + (drm_i810_private_t *) dev->dev_private; + + if(dev_priv->ring.virtual_start) { + drm_ioremapfree((void *) dev_priv->ring.virtual_start, + dev_priv->ring.Size); } - if (dma->this_buffer) { - drm_free_buffer(dev, dma->this_buffer); - dma->this_buffer = NULL; + if(dev_priv->hw_status_page != 0UL) { + i810_free_page(dev, dev_priv->hw_status_page); + /* Need to rewrite hardware status page */ + I810_WRITE(0x02080, 0x1ffff000); } - clear_bit(0, &dev->dma_flag); - - /* Dispatch new buffer */ - queue_task(&dev->tq, &tq_immediate); - mark_bh(IMMEDIATE_BH); + drm_free(dev->dev_private, sizeof(drm_i810_private_t), + DRM_MEM_DRIVER); + dev->dev_private = NULL; } + return 0; } -/* Only called by i810_dma_schedule. */ -static int i810_do_dma(drm_device_t *dev, int locked) +static int i810_wait_ring(drm_device_t *dev, int n) { - unsigned long address; - unsigned long length; - drm_buf_t *buf; - int retcode = 0; - drm_device_dma_t *dma = dev->dma; -#if DRM_DMA_HISTOGRAM - cycles_t dma_start, dma_stop; -#endif - - if (test_and_set_bit(0, &dev->dma_flag)) { - atomic_inc(&dma->total_missed_dma); - return -EBUSY; - } - -#if DRM_DMA_HISTOGRAM - dma_start = get_cycles(); -#endif - - if (!dma->next_buffer) { - DRM_ERROR("No next_buffer\n"); - clear_bit(0, &dev->dma_flag); - return -EINVAL; - } - - buf = dma->next_buffer; - address = (unsigned long)buf->bus_address; - length = buf->used; + drm_i810_private_t *dev_priv = dev->dev_private; + drm_i810_ring_buffer_t *ring = &(dev_priv->ring); + int iters = 0; + unsigned long end; + + end = jiffies + (HZ*3); + while (ring->space < n) { + int i; - - DRM_DEBUG("context %d, buffer %d (%ld bytes)\n", - buf->context, buf->idx, length); - - if (buf->list == DRM_LIST_RECLAIM) { - drm_clear_next_buffer(dev); - drm_free_buffer(dev, buf); - clear_bit(0, &dev->dma_flag); - return -EINVAL; - } - - if (!length) { - DRM_ERROR("0 length buffer\n"); - drm_clear_next_buffer(dev); - drm_free_buffer(dev, buf); - clear_bit(0, &dev->dma_flag); - return 0; - } - - if (!i810_dma_is_ready(dev)) { - clear_bit(0, &dev->dma_flag); - return -EBUSY; - } - - if (buf->while_locked) { - if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { - DRM_ERROR("Dispatching buffer %d from pid %d" - " \"while locked\", but no lock held\n", - buf->idx, buf->pid); - } - } else { - if (!locked && !drm_lock_take(&dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT)) { - atomic_inc(&dma->total_missed_lock); - clear_bit(0, &dev->dma_flag); - return -EBUSY; + ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR; + ring->space = ring->head - (ring->tail+8); + + if (ring->space < 0) ring->space += ring->Size; + + iters++; + if((signed)(end - jiffies) <= 0) { + DRM_ERROR("space: %d wanted %d\n", ring->space, n); + DRM_ERROR("lockup\n"); + goto out_wait_ring; } - } - - if (dev->last_context != buf->context - && !(dev->queuelist[buf->context]->flags - & _DRM_CONTEXT_PRESERVED)) { - /* PRE: dev->last_context != buf->context */ - if (drm_context_switch(dev, dev->last_context, buf->context)) { - drm_clear_next_buffer(dev); - drm_free_buffer(dev, buf); - } - retcode = -EBUSY; - goto cleanup; - - /* POST: we will wait for the context - switch and will dispatch on a later call - when dev->last_context == buf->context. - NOTE WE HOLD THE LOCK THROUGHOUT THIS - TIME! */ - } - - drm_clear_next_buffer(dev); - buf->pending = 1; - buf->waiting = 0; - buf->list = DRM_LIST_PEND; -#if DRM_DMA_HISTOGRAM - buf->time_dispatched = get_cycles(); -#endif - i810_dma_dispatch(dev, address, length); - drm_free_buffer(dev, dma->this_buffer); - dma->this_buffer = buf; - - atomic_add(length, &dma->total_bytes); - atomic_inc(&dma->total_dmas); - - if (!buf->while_locked && !dev->context_flag && !locked) { - if (drm_lock_free(dev, &dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT)) { - DRM_ERROR("\n"); - } + for (i = 0 ; i < 2000 ; i++) ; } -cleanup: - - clear_bit(0, &dev->dma_flag); -#if DRM_DMA_HISTOGRAM - dma_stop = get_cycles(); - atomic_inc(&dev->histo.dma[drm_histogram_slot(dma_stop - dma_start)]); -#endif - - return retcode; -} - -static void i810_dma_schedule_timer_wrapper(unsigned long dev) -{ - i810_dma_schedule((drm_device_t *)dev, 0); +out_wait_ring: + return iters; } -static void i810_dma_schedule_tq_wrapper(void *dev) +static void i810_kernel_lost_context(drm_device_t *dev) { - i810_dma_schedule(dev, 0); + drm_i810_private_t *dev_priv = dev->dev_private; + drm_i810_ring_buffer_t *ring = &(dev_priv->ring); + + ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR; + ring->tail = I810_READ(LP_RING + RING_TAIL); + ring->space = ring->head - (ring->tail+8); + if (ring->space < 0) ring->space += ring->Size; } -int i810_dma_schedule(drm_device_t *dev, int locked) +static int i810_freelist_init(drm_device_t *dev) { - int next; - drm_queue_t *q; - drm_buf_t *buf; - int retcode = 0; - int processed = 0; - int missed; - int expire = 20; - drm_device_dma_t *dma = dev->dma; -#if DRM_DMA_HISTOGRAM - cycles_t schedule_start; -#endif - - if (test_and_set_bit(0, &dev->interrupt_flag)) { - /* Not reentrant */ - atomic_inc(&dma->total_missed_sched); - return -EBUSY; - } - missed = atomic_read(&dma->total_missed_sched); - -#if DRM_DMA_HISTOGRAM - schedule_start = get_cycles(); -#endif - -again: - if (dev->context_flag) { - clear_bit(0, &dev->interrupt_flag); - return -EBUSY; - } - if (dma->next_buffer) { - /* Unsent buffer that was previously - selected, but that couldn't be sent - because the lock could not be obtained - or the DMA engine wasn't ready. Try - again. */ - atomic_inc(&dma->total_tried); - if (!(retcode = i810_do_dma(dev, locked))) { - atomic_inc(&dma->total_hit); - ++processed; - } - } else { - do { - next = drm_select_queue(dev, - i810_dma_schedule_timer_wrapper); - if (next >= 0) { - q = dev->queuelist[next]; - buf = drm_waitlist_get(&q->waitlist); - dma->next_buffer = buf; - dma->next_queue = q; - if (buf && buf->list == DRM_LIST_RECLAIM) { - drm_clear_next_buffer(dev); - drm_free_buffer(dev, buf); - } - } - } while (next >= 0 && !dma->next_buffer); - if (dma->next_buffer) { - if (!(retcode = i810_do_dma(dev, locked))) { - ++processed; - } - } + drm_device_dma_t *dma = dev->dma; + drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; + u8 *hw_status = (u8 *)dev_priv->hw_status_page; + int i; + int my_idx = 24; + + if(dma->buf_count > 1019) { + /* Not enough space in the status page for the freelist */ + return -EINVAL; } - if (--expire) { - if (missed != atomic_read(&dma->total_missed_sched)) { - atomic_inc(&dma->total_lost); - if (i810_dma_is_ready(dev)) goto again; - } - if (processed && i810_dma_is_ready(dev)) { - atomic_inc(&dma->total_lost); - processed = 0; - goto again; - } + for (i = 0; i < dma->buf_count; i++) { + drm_buf_t *buf = dma->buflist[ i ]; + drm_i810_buf_priv_t *buf_priv = buf->dev_private; + + buf_priv->in_use = hw_status + my_idx; + DRM_DEBUG("buf_priv->in_use : %p\n", buf_priv->in_use); + *buf_priv->in_use = I810_BUF_FREE; + buf_priv->my_use_idx = my_idx; + my_idx += 4; } - - clear_bit(0, &dev->interrupt_flag); - -#if DRM_DMA_HISTOGRAM - atomic_inc(&dev->histo.schedule[drm_histogram_slot(get_cycles() - - schedule_start)]); -#endif - return retcode; + return 0; } -static int i810_dma_priority(drm_device_t *dev, drm_dma_t *d) +static int i810_dma_initialize(drm_device_t *dev, + drm_i810_private_t *dev_priv, + drm_i810_init_t *init) { - unsigned long address; - unsigned long length; - int must_free = 0; - int retcode = 0; - int i; - int idx; - drm_buf_t *buf; - drm_buf_t *last_buf = NULL; - drm_device_dma_t *dma = dev->dma; - DECLARE_WAITQUEUE(entry, current); - - /* Turn off interrupt handling */ - while (test_and_set_bit(0, &dev->interrupt_flag)) { - schedule(); - if (signal_pending(current)) return -EINTR; - } - if (!(d->flags & _DRM_DMA_WHILE_LOCKED)) { - while (!drm_lock_take(&dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT)) { - schedule(); - if (signal_pending(current)) { - clear_bit(0, &dev->interrupt_flag); - return -EINTR; - } - } - ++must_free; - } - atomic_inc(&dma->total_prio); - - for (i = 0; i < d->send_count; i++) { - idx = d->send_indices[i]; - if (idx < 0 || idx >= dma->buf_count) { - DRM_ERROR("Index %d (of %d max)\n", - d->send_indices[i], dma->buf_count - 1); - continue; - } - buf = dma->buflist[ idx ]; - if (buf->pid != current->pid) { - DRM_ERROR("Process %d using buffer owned by %d\n", - current->pid, buf->pid); - retcode = -EINVAL; - goto cleanup; - } - if (buf->list != DRM_LIST_NONE) { - DRM_ERROR("Process %d using %d's buffer on list %d\n", - current->pid, buf->pid, buf->list); - retcode = -EINVAL; - goto cleanup; - } - /* This isn't a race condition on - buf->list, since our concern is the - buffer reclaim during the time the - process closes the /dev/drm? handle, so - it can't also be doing DMA. */ - buf->list = DRM_LIST_PRIO; - buf->used = d->send_sizes[i]; - buf->context = d->context; - buf->while_locked = d->flags & _DRM_DMA_WHILE_LOCKED; - address = (unsigned long)buf->address; - length = buf->used; - if (!length) { - DRM_ERROR("0 length buffer\n"); - } - if (buf->pending) { - DRM_ERROR("Sending pending buffer:" - " buffer %d, offset %d\n", - d->send_indices[i], i); - retcode = -EINVAL; - goto cleanup; - } - if (buf->waiting) { - DRM_ERROR("Sending waiting buffer:" - " buffer %d, offset %d\n", - d->send_indices[i], i); - retcode = -EINVAL; - goto cleanup; - } - buf->pending = 1; - - if (dev->last_context != buf->context - && !(dev->queuelist[buf->context]->flags - & _DRM_CONTEXT_PRESERVED)) { - add_wait_queue(&dev->context_wait, &entry); - current->state = TASK_INTERRUPTIBLE; - /* PRE: dev->last_context != buf->context */ - drm_context_switch(dev, dev->last_context, - buf->context); - /* POST: we will wait for the context - switch and will dispatch on a later call - when dev->last_context == buf->context. - NOTE WE HOLD THE LOCK THROUGHOUT THIS - TIME! */ - schedule(); - current->state = TASK_RUNNING; - remove_wait_queue(&dev->context_wait, &entry); - if (signal_pending(current)) { - retcode = -EINTR; - goto cleanup; - } - if (dev->last_context != buf->context) { - DRM_ERROR("Context mismatch: %d %d\n", - dev->last_context, - buf->context); - } - } - -#if DRM_DMA_HISTOGRAM - buf->time_queued = get_cycles(); - buf->time_dispatched = buf->time_queued; -#endif - i810_dma_dispatch(dev, address, length); - if (drm_lock_free(dev, &dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT)) { - DRM_ERROR("\n"); - } - - atomic_add(length, &dma->total_bytes); - atomic_inc(&dma->total_dmas); - - if (last_buf) { - drm_free_buffer(dev, last_buf); - } - last_buf = buf; - } + drm_map_t *sarea_map; + dev->dev_private = (void *) dev_priv; + memset(dev_priv, 0, sizeof(drm_i810_private_t)); -cleanup: - if (last_buf) { - i810_dma_ready(dev); - drm_free_buffer(dev, last_buf); + if (init->ring_map_idx >= dev->map_count || + init->buffer_map_idx >= dev->map_count) { + i810_dma_cleanup(dev); + DRM_ERROR("ring_map or buffer_map are invalid\n"); + return -EINVAL; } - - if (must_free && !dev->context_flag) { - if (drm_lock_free(dev, &dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT)) { - DRM_ERROR("\n"); - } + + dev_priv->ring_map_idx = init->ring_map_idx; + dev_priv->buffer_map_idx = init->buffer_map_idx; + sarea_map = dev->maplist[0]; + dev_priv->sarea_priv = (drm_i810_sarea_t *) + ((u8 *)sarea_map->handle + + init->sarea_priv_offset); + + atomic_set(&dev_priv->flush_done, 0); + init_waitqueue_head(&dev_priv->flush_queue); + + dev_priv->ring.Start = init->ring_start; + dev_priv->ring.End = init->ring_end; + dev_priv->ring.Size = init->ring_size; + dev_priv->ring.virtual_start = drm_ioremap(dev->agp->base + + init->ring_start, + init->ring_size); + dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; + + if (dev_priv->ring.virtual_start == NULL) { + i810_dma_cleanup(dev); + DRM_ERROR("can not ioremap virtual address for" + " ring buffer\n"); + return -ENOMEM; } - clear_bit(0, &dev->interrupt_flag); - return retcode; + + /* Program Hardware Status Page */ + dev_priv->hw_status_page = i810_alloc_page(dev); + memset((void *) dev_priv->hw_status_page, 0, PAGE_SIZE); + if(dev_priv->hw_status_page == 0UL) { + i810_dma_cleanup(dev); + DRM_ERROR("Can not allocate hardware status page\n"); + return -ENOMEM; + } + DRM_DEBUG("hw status page @ %lx\n", dev_priv->hw_status_page); + + I810_WRITE(0x02080, virt_to_bus((void *)dev_priv->hw_status_page)); + DRM_DEBUG("Enabled hardware status page\n"); + + /* Now we need to init our freelist */ + if(i810_freelist_init(dev) != 0) { + i810_dma_cleanup(dev); + DRM_ERROR("Not enough space in the status page for" + " the freelist\n"); + return -ENOMEM; + } + return 0; } -static int i810_dma_send_buffers(drm_device_t *dev, drm_dma_t *d) +int i810_dma_init(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) { - DECLARE_WAITQUEUE(entry, current); - drm_buf_t *last_buf = NULL; - int retcode = 0; - drm_device_dma_t *dma = dev->dma; - - if (d->flags & _DRM_DMA_BLOCK) { - last_buf = dma->buflist[d->send_indices[d->send_count-1]]; - add_wait_queue(&last_buf->dma_wait, &entry); - } + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_i810_private_t *dev_priv; + drm_i810_init_t init; + int retcode = 0; - if ((retcode = drm_dma_enqueue(dev, d))) { - if (d->flags & _DRM_DMA_BLOCK) - remove_wait_queue(&last_buf->dma_wait, &entry); - return retcode; - } - - i810_dma_schedule(dev, 0); + copy_from_user_ret(&init, (drm_i810_init_t *)arg, + sizeof(init), -EFAULT); - if (d->flags & _DRM_DMA_BLOCK) { - DRM_DEBUG("%d waiting\n", current->pid); - current->state = TASK_INTERRUPTIBLE; - for (;;) { - if (!last_buf->waiting - && !last_buf->pending) - break; /* finished */ - schedule(); - if (signal_pending(current)) { - retcode = -EINTR; /* Can't restart */ - break; - } - } - current->state = TASK_RUNNING; - DRM_DEBUG("%d running\n", current->pid); - remove_wait_queue(&last_buf->dma_wait, &entry); - if (!retcode - || (last_buf->list==DRM_LIST_PEND && !last_buf->pending)) { - if (!waitqueue_active(&last_buf->dma_wait)) { - drm_free_buffer(dev, last_buf); - } - } - if (retcode) { - DRM_ERROR("ctx%d w%d p%d c%d i%d l%d %d/%d\n", - d->context, - last_buf->waiting, - last_buf->pending, - DRM_WAITCOUNT(dev, d->context), - last_buf->idx, - last_buf->list, - last_buf->pid, - current->pid); - } + switch(init.func) { + case I810_INIT_DMA: + dev_priv = drm_alloc(sizeof(drm_i810_private_t), + DRM_MEM_DRIVER); + if(dev_priv == NULL) return -ENOMEM; + retcode = i810_dma_initialize(dev, dev_priv, &init); + break; + case I810_CLEANUP_DMA: + retcode = i810_dma_cleanup(dev); + break; + default: + retcode = -EINVAL; + break; } - return retcode; + + return retcode; } -int i810_dma(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) +static void i810_dma_dispatch_general(drm_device_t *dev, drm_buf_t *buf, + int used ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - drm_device_dma_t *dma = dev->dma; - int retcode = 0; - drm_dma_t d; - - printk("i810_dma start\n"); - copy_from_user_ret(&d, (drm_dma_t *)arg, sizeof(d), -EFAULT); - DRM_DEBUG("%d %d: %d send, %d req\n", - current->pid, d.context, d.send_count, d.request_count); + drm_i810_private_t *dev_priv = dev->dev_private; + drm_i810_buf_priv_t *buf_priv = buf->dev_private; + unsigned long address = (unsigned long)buf->bus_address; + unsigned long start = address - dev->agp->base; + RING_LOCALS; + + dev_priv->counter++; + DRM_DEBUG( "dispatch counter : %ld\n", dev_priv->counter); + DRM_DEBUG( "i810_dma_dispatch\n"); + DRM_DEBUG( "start : 0x%lx\n", start); + DRM_DEBUG( "used : 0x%x\n", used); + DRM_DEBUG( "start + used - 4 : 0x%lx\n", start + used - 4); + i810_kernel_lost_context(dev); + + BEGIN_LP_RING(10); + OUT_RING( CMD_OP_BATCH_BUFFER ); + OUT_RING( start | BB1_PROTECTED ); + OUT_RING( start + used - 4 ); + OUT_RING( CMD_STORE_DWORD_IDX ); + OUT_RING( 20 ); + OUT_RING( dev_priv->counter ); + OUT_RING( CMD_STORE_DWORD_IDX ); + OUT_RING( buf_priv->my_use_idx ); + OUT_RING( I810_BUF_FREE ); + OUT_RING( CMD_REPORT_HEAD ); + ADVANCE_LP_RING(); +} - if (d.context == DRM_KERNEL_CONTEXT || d.context >= dev->queue_slots) { - DRM_ERROR("Process %d using context %d\n", - current->pid, d.context); - return -EINVAL; - } +static void i810_dma_dispatch_vertex(drm_device_t *dev, + drm_buf_t *buf, + int discard, + int used) +{ + drm_i810_private_t *dev_priv = dev->dev_private; + drm_i810_buf_priv_t *buf_priv = buf->dev_private; + drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_clip_rect_t *box = sarea_priv->boxes; + int nbox = sarea_priv->nbox; + unsigned long address = (unsigned long)buf->bus_address; + unsigned long start = address - dev->agp->base; + int i = 0; + RING_LOCALS; - 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, d.send_count, dma->buf_count); - return -EINVAL; - } - 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 (nbox > I810_NR_SAREA_CLIPRECTS) + nbox = I810_NR_SAREA_CLIPRECTS; + + DRM_DEBUG("dispatch vertex addr 0x%lx, used 0x%x nbox %d\n", + address, used, nbox); + + dev_priv->counter++; + DRM_DEBUG( "dispatch counter : %ld\n", dev_priv->counter); + DRM_DEBUG( "i810_dma_dispatch\n"); + DRM_DEBUG( "start : %lx\n", start); + DRM_DEBUG( "used : %d\n", used); + DRM_DEBUG( "start + used - 4 : %ld\n", start + used - 4); + i810_kernel_lost_context(dev); + + if (used) { + do { + if (i < nbox) { + BEGIN_LP_RING(4); + OUT_RING( GFX_OP_SCISSOR | SC_UPDATE_SCISSOR | + SC_ENABLE ); + OUT_RING( GFX_OP_SCISSOR_INFO ); + OUT_RING( box[i].x1 | (box[i].y1 << 16) ); + OUT_RING( (box[i].x2-1) | ((box[i].y2-1)<<16) ); + ADVANCE_LP_RING(); + } + + BEGIN_LP_RING(4); + OUT_RING( CMD_OP_BATCH_BUFFER ); + OUT_RING( start | BB1_PROTECTED ); + OUT_RING( start + used - 4 ); + OUT_RING( 0 ); + ADVANCE_LP_RING(); + + } while (++i < nbox); } - if (d.send_count) { -#if 0 - if (d.flags & _DRM_DMA_PRIORITY) - retcode = i810_dma_priority(dev, &d); - else - retcode = i810_dma_send_buffers(dev, &d); -#endif - printk("i810_dma priority\n"); + BEGIN_LP_RING(10); + OUT_RING( CMD_STORE_DWORD_IDX ); + OUT_RING( 20 ); + OUT_RING( dev_priv->counter ); + OUT_RING( 0 ); - retcode = i810_dma_priority(dev, &d); + if (discard) { + OUT_RING( CMD_STORE_DWORD_IDX ); + OUT_RING( buf_priv->my_use_idx ); + OUT_RING( I810_BUF_FREE ); + OUT_RING( 0 ); } - d.granted_count = 0; + OUT_RING( CMD_REPORT_HEAD ); + OUT_RING( 0 ); + ADVANCE_LP_RING(); +} - if (!retcode && d.request_count) { - retcode = drm_dma_get_buffers(dev, &d); - } - DRM_DEBUG("%d returning, granted = %d\n", - current->pid, d.granted_count); - copy_to_user_ret((drm_dma_t *)arg, &d, sizeof(d), -EFAULT); +/* Interrupts are only for flushing */ +static void i810_dma_service(int irq, void *device, struct pt_regs *regs) +{ + drm_device_t *dev = (drm_device_t *)device; + u16 temp; + + atomic_inc(&dev->total_irq); + temp = I810_READ16(I810REG_INT_IDENTITY_R); + temp = temp & ~(0x6000); + if(temp != 0) I810_WRITE16(I810REG_INT_IDENTITY_R, + temp); /* Clear all interrupts */ + + queue_task(&dev->tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} - printk("i810_dma end (granted)\n"); - return retcode; +static void i810_dma_task_queue(void *device) +{ + drm_device_t *dev = (drm_device_t *) device; + drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; + + atomic_set(&dev_priv->flush_done, 1); + wake_up_interruptible(&dev_priv->flush_queue); } int i810_irq_install(drm_device_t *dev, int irq) { int retcode; - + u16 temp; + if (!irq) return -EINVAL; down(&dev->struct_sem); @@ -591,6 +508,7 @@ int i810_irq_install(drm_device_t *dev, int irq) dev->irq = irq; up(&dev->struct_sem); + DRM_DEBUG( "Interrupt Install : %d\n", irq); DRM_DEBUG("%d\n", irq); dev->context_flag = 0; @@ -603,12 +521,21 @@ int i810_irq_install(drm_device_t *dev, int irq) dev->tq.next = NULL; dev->tq.sync = 0; - dev->tq.routine = i810_dma_schedule_tq_wrapper; + dev->tq.routine = i810_dma_task_queue; dev->tq.data = dev; - /* Before installing handler */ - /* TODO */ + temp = I810_READ16(I810REG_HWSTAM); + temp = temp & 0x6000; + I810_WRITE16(I810REG_HWSTAM, temp); + + temp = I810_READ16(I810REG_INT_MASK_R); + temp = temp & 0x6000; + I810_WRITE16(I810REG_INT_MASK_R, temp); /* Unmask interrupts */ + temp = I810_READ16(I810REG_INT_ENABLE_R); + temp = temp & 0x6000; + I810_WRITE16(I810REG_INT_ENABLE_R, temp); /* Disable all interrupts */ + /* Install handler */ if ((retcode = request_irq(dev->irq, i810_dma_service, @@ -620,15 +547,18 @@ int i810_irq_install(drm_device_t *dev, int irq) up(&dev->struct_sem); return retcode; } - - /* After installing handler */ - /* TODO */ + temp = I810_READ16(I810REG_INT_ENABLE_R); + temp = temp & 0x6000; + temp = temp | 0x0003; + I810_WRITE16(I810REG_INT_ENABLE_R, + temp); /* Enable bp & user interrupts */ return 0; } int i810_irq_uninstall(drm_device_t *dev) { int irq; + u16 temp; down(&dev->struct_sem); irq = dev->irq; @@ -636,16 +566,25 @@ int i810_irq_uninstall(drm_device_t *dev) up(&dev->struct_sem); if (!irq) return -EINVAL; - + + DRM_DEBUG( "Interrupt UnInstall: %d\n", irq); DRM_DEBUG("%d\n", irq); - - /* TODO : Disable interrupts */ + + temp = I810_READ16(I810REG_INT_IDENTITY_R); + temp = temp & ~(0x6000); + if(temp != 0) I810_WRITE16(I810REG_INT_IDENTITY_R, + temp); /* Clear all interrupts */ + + temp = I810_READ16(I810REG_INT_ENABLE_R); + temp = temp & 0x6000; + I810_WRITE16(I810REG_INT_ENABLE_R, + temp); /* Disable all interrupts */ + free_irq(irq, dev); return 0; } - int i810_control(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -654,8 +593,7 @@ int i810_control(struct inode *inode, struct file *filp, unsigned int cmd, drm_control_t ctl; int retcode; - printk(KERN_INFO "i810_control\n"); - i810_dma_init(dev); + DRM_DEBUG( "i810_control\n"); copy_from_user_ret(&ctl, (drm_control_t *)arg, sizeof(ctl), -EFAULT); @@ -674,20 +612,134 @@ int i810_control(struct inode *inode, struct file *filp, unsigned int cmd, return 0; } +static inline void i810_dma_emit_flush(drm_device_t *dev) +{ + drm_i810_private_t *dev_priv = dev->dev_private; + RING_LOCALS; + + i810_kernel_lost_context(dev); + BEGIN_LP_RING(2); + OUT_RING( CMD_REPORT_HEAD ); + OUT_RING( GFX_OP_USER_INTERRUPT ); + ADVANCE_LP_RING(); +} + +static inline void i810_dma_quiescent_emit(drm_device_t *dev) +{ + drm_i810_private_t *dev_priv = dev->dev_private; + RING_LOCALS; + + i810_kernel_lost_context(dev); + BEGIN_LP_RING(4); + + OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE ); + OUT_RING( CMD_REPORT_HEAD ); + OUT_RING( GFX_OP_USER_INTERRUPT ); + OUT_RING( 0 ); + ADVANCE_LP_RING(); +} + +static void i810_dma_quiescent(drm_device_t *dev) +{ + DECLARE_WAITQUEUE(entry, current); + drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; + unsigned long end; + + if(dev_priv == NULL) { + return; + } + atomic_set(&dev_priv->flush_done, 0); + current->state = TASK_INTERRUPTIBLE; + add_wait_queue(&dev_priv->flush_queue, &entry); + end = jiffies + (HZ*3); + + for (;;) { + i810_dma_quiescent_emit(dev); + if (atomic_read(&dev_priv->flush_done) == 1) break; + if((signed)(end - jiffies) <= 0) { + DRM_ERROR("lockup\n"); + break; + } + schedule_timeout(HZ*3); + if (signal_pending(current)) { + break; + } + } + + current->state = TASK_RUNNING; + remove_wait_queue(&dev_priv->flush_queue, &entry); + + return; +} + +static int i810_flush_queue(drm_device_t *dev) +{ + DECLARE_WAITQUEUE(entry, current); + drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; + unsigned long end; + int ret = 0; + + if(dev_priv == NULL) { + return 0; + } + atomic_set(&dev_priv->flush_done, 0); + current->state = TASK_INTERRUPTIBLE; + add_wait_queue(&dev_priv->flush_queue, &entry); + end = jiffies + (HZ*3); + for (;;) { + i810_dma_emit_flush(dev); + if (atomic_read(&dev_priv->flush_done) == 1) break; + if((signed)(end - jiffies) <= 0) { + DRM_ERROR("lockup\n"); + break; + } + schedule_timeout(HZ*3); + if (signal_pending(current)) { + ret = -EINTR; /* Can't restart */ + break; + } + } + + current->state = TASK_RUNNING; + remove_wait_queue(&dev_priv->flush_queue, &entry); + + return ret; +} + +/* Must be called with the lock held */ +void i810_reclaim_buffers(drm_device_t *dev, pid_t pid) +{ + drm_device_dma_t *dma = dev->dma; + int i; + + if (!dma) return; + if(dev->dev_private == NULL) return; + + i810_flush_queue(dev); + + for (i = 0; i < dma->buf_count; i++) { + drm_buf_t *buf = dma->buflist[ i ]; + drm_i810_buf_priv_t *buf_priv = buf->dev_private; + + if (buf->pid == pid) { + /* Only buffers that need to get reclaimed ever + * get set to free */ + if(buf_priv == NULL) return; + cmpxchg(buf_priv->in_use, + I810_BUF_USED, I810_BUF_FREE); + } + } +} + int i810_lock(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; + DECLARE_WAITQUEUE(entry, current); int ret = 0; drm_lock_t lock; - drm_queue_t *q; -#if DRM_DMA_HISTOGRAM - cycles_t start; - - dev->lck_start = start = get_cycles(); -#endif copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT); @@ -696,16 +748,20 @@ int i810_lock(struct inode *inode, struct file *filp, unsigned int cmd, current->pid, lock.context); return -EINVAL; } + + DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n", + lock.context, current->pid, dev->lock.hw_lock->lock, + lock.flags); - if (lock.context < 0 || lock.context >= dev->queue_count) { + if (lock.context < 0) { return -EINVAL; } - q = dev->queuelist[lock.context]; - - ret = drm_flush_block_and_flush(dev, lock.context, lock.flags); + /* Only one queue: + */ if (!ret) { - if (_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) +#if 0 + if (_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) != lock.context) { long j = jiffies - dev->lock.lock_time; @@ -716,6 +772,7 @@ int i810_lock(struct inode *inode, struct file *filp, unsigned int cmd, schedule_timeout(j); } } +#endif add_wait_queue(&dev->lock.lock_queue, &entry); for (;;) { if (!dev->lock.hw_lock) { @@ -728,13 +785,13 @@ int i810_lock(struct inode *inode, struct file *filp, unsigned int cmd, dev->lock.pid = current->pid; dev->lock.lock_time = jiffies; atomic_inc(&dev->total_locks); - atomic_inc(&q->total_locks); break; /* Got lock */ } /* Contention */ atomic_inc(&dev->total_sleeps); current->state = TASK_INTERRUPTIBLE; + DRM_DEBUG("Calling lock schedule\n"); schedule(); if (signal_pending(current)) { ret = -ERESTARTSYS; @@ -744,19 +801,184 @@ int i810_lock(struct inode *inode, struct file *filp, unsigned int cmd, current->state = TASK_RUNNING; remove_wait_queue(&dev->lock.lock_queue, &entry); } - - drm_flush_unblock(dev, lock.context, lock.flags); /* cleanup phase */ if (!ret) { - if (lock.flags & _DRM_LOCK_READY) - i810_dma_ready(dev); - if (lock.flags & _DRM_LOCK_QUIESCENT) - i810_dma_quiescent(dev); + if (lock.flags & _DRM_LOCK_QUIESCENT) { + DRM_DEBUG("_DRM_LOCK_QUIESCENT\n"); + DRM_DEBUG("fred\n"); + i810_dma_quiescent(dev); + } } + DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock"); + return ret; +} -#if DRM_DMA_HISTOGRAM - atomic_inc(&dev->histo.lacq[drm_histogram_slot(get_cycles() - start)]); -#endif +int i810_flush_ioctl(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_DEBUG("i810_flush_ioctl\n"); + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i810_flush_ioctl called without lock held\n"); + return -EINVAL; + } + + i810_flush_queue(dev); + return 0; +} + +static int i810DmaGeneral(drm_device_t *dev, drm_i810_general_t *args) +{ + drm_device_dma_t *dma = dev->dma; + drm_buf_t *buf = dma->buflist[ args->idx ]; + + if (!args->used) { + i810_freelist_put(dev, buf); + } else { + i810_dma_dispatch_general( dev, buf, args->used ); + atomic_add(args->used, &dma->total_bytes); + atomic_inc(&dma->total_dmas); + } + return 0; +} + +static int i810DmaVertex(drm_device_t *dev, drm_i810_vertex_t *args) +{ + drm_device_dma_t *dma = dev->dma; + drm_buf_t *buf = dma->buflist[ args->idx ]; + i810_dma_dispatch_vertex( dev, buf, args->discard, args->used ); + atomic_add(args->used, &dma->total_bytes); + atomic_inc(&dma->total_dmas); + return 0; +} + +int i810_dma_general(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_i810_general_t general; + drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; + u32 *hw_status = (u32 *)dev_priv->hw_status_page; + drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) + dev_priv->sarea_priv; + + int retcode = 0; - return ret; + copy_from_user_ret(&general, (drm_i810_general_t *)arg, sizeof(general), + -EFAULT); + + DRM_DEBUG("i810 dma general idx %d used %d\n", + general.idx, general.used); + + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i810_dma_general called without lock held\n"); + return -EINVAL; + } + + retcode = i810DmaGeneral(dev, &general); + sarea_priv->last_enqueue = dev_priv->counter-1; + sarea_priv->last_dispatch = (int) hw_status[5]; + + return retcode; +} + +int i810_dma_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_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; + u32 *hw_status = (u32 *)dev_priv->hw_status_page; + drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) + dev_priv->sarea_priv; + drm_i810_vertex_t vertex; + int retcode = 0; + + copy_from_user_ret(&vertex, (drm_i810_vertex_t *)arg, sizeof(vertex), + -EFAULT); + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i810_dma_vertex called without lock held\n"); + return -EINVAL; + } + + DRM_DEBUG("i810 dma vertex, idx %d used %d discard %d\n", + vertex.idx, vertex.used, vertex.discard); + + retcode = i810DmaVertex(dev, &vertex); + sarea_priv->last_enqueue = dev_priv->counter-1; + sarea_priv->last_dispatch = (int) hw_status[5]; + + return retcode; + +} + +int i810_getage(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_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; + u32 *hw_status = (u32 *)dev_priv->hw_status_page; + drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) + dev_priv->sarea_priv; + + sarea_priv->last_dispatch = (int) hw_status[5]; + return 0; +} + +int i810_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_device_dma_t *dma = dev->dma; + int retcode = 0; + drm_dma_t d; + drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; + u32 *hw_status = (u32 *)dev_priv->hw_status_page; + drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) + dev_priv->sarea_priv; + + + copy_from_user_ret(&d, (drm_dma_t *)arg, sizeof(d), -EFAULT); + DRM_DEBUG("%d %d: %d send, %d req\n", + current->pid, d.context, d.send_count, d.request_count); + + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i810_dma called without lock held\n"); + return -EINVAL; + } + + /* Please don't send us buffers. + */ + if (d.send_count != 0) { + DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n", + current->pid, d.send_count); + return -EINVAL; + } + + /* We'll send you buffers. + */ + 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; + } + + d.granted_count = 0; + + if (!retcode && d.request_count) { + retcode = i810_dma_get_buffers(dev, &d); + } + + DRM_DEBUG("i810_dma: %d returning, granted = %d\n", + current->pid, d.granted_count); + + copy_to_user_ret((drm_dma_t *)arg, &d, sizeof(d), -EFAULT); + sarea_priv->last_dispatch = (int) hw_status[5]; + + return retcode; } diff --git a/linux/i810_drm.h b/linux/i810_drm.h new file mode 100644 index 000000000..0754874c6 --- /dev/null +++ b/linux/i810_drm.h @@ -0,0 +1,93 @@ +#ifndef _I810_DRM_H_ +#define _I810_DRM_H_ + +/* WARNING: These defines must be the same as what the Xserver uses. + * if you change them, you must change the defines in the Xserver. + */ + +/* Might one day want to support the client-side ringbuffer code again. + */ +#ifndef _I810_DEFINES_ +#define _I810_DEFINES_ + +#define I810_USE_BATCH 1 +#define I810_DMA_BUF_ORDER 12 +#define I810_DMA_BUF_SZ (1<device = MKDEV(MISC_MAJOR, i810_misc.minor); dev->name = I810_NAME; - printk("doing mem init\n"); + DRM_DEBUG("doing mem init\n"); drm_mem_init(); - printk("doing proc init\n"); + DRM_DEBUG("doing proc init\n"); drm_proc_init(dev); - printk("doing agp init\n"); + DRM_DEBUG("doing agp init\n"); dev->agp = drm_agp_init(); - printk("doing ctxbitmap init\n"); + if(dev->agp == NULL) { + DRM_INFO("The i810 drm module requires the agpgart module" + " to function correctly\nPlease load the agpgart" + " module before you load the i810 module\n"); + drm_proc_cleanup(); + misc_deregister(&i810_misc); + i810_takedown(dev); + return -ENOMEM; + } + DRM_DEBUG("doing ctxbitmap init\n"); if((retcode = drm_ctxbitmap_init(dev))) { DRM_ERROR("Cannot allocate memory for context bitmap.\n"); drm_proc_cleanup(); @@ -386,10 +403,6 @@ int i810_init(void) i810_takedown(dev); return retcode; } -#if 0 - printk("doing i810_dma_init\n"); - i810_dma_init(dev); -#endif DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", I810_NAME, @@ -417,7 +430,6 @@ void i810_cleanup(void) DRM_INFO("Module unloaded\n"); } drm_ctxbitmap_cleanup(dev); - i810_dma_cleanup(dev); i810_takedown(dev); if (dev->agp) { drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS); @@ -484,24 +496,82 @@ int i810_release(struct inode *inode, struct file *filp) drm_device_t *dev = priv->dev; int retcode = 0; - DRM_DEBUG("open_count = %d\n", dev->open_count); - if (!(retcode = drm_release(inode, filp))) { - MOD_DEC_USE_COUNT; - atomic_inc(&dev->total_close); - spin_lock(&dev->count_lock); - if (!--dev->open_count) { - if (atomic_read(&dev->ioctl_count) || dev->blocked) { - DRM_ERROR("Device busy: %d %d\n", - atomic_read(&dev->ioctl_count), - dev->blocked); - spin_unlock(&dev->count_lock); - return -EBUSY; + DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n", + current->pid, dev->device, dev->open_count); + + if (_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) + && dev->lock.pid == current->pid) { + i810_reclaim_buffers(dev, priv->pid); + DRM_ERROR("Process %d dead, freeing lock for context %d\n", + current->pid, + _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); + drm_lock_free(dev, + &dev->lock.hw_lock->lock, + _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); + + /* FIXME: may require heavy-handed reset of + hardware at this point, possibly + processed via a callback to the X + server. */ + } else { + /* The lock is required to reclaim buffers */ + DECLARE_WAITQUEUE(entry, current); + add_wait_queue(&dev->lock.lock_queue, &entry); + for (;;) { + if (!dev->lock.hw_lock) { + /* Device has been unregistered */ + retcode = -EINTR; + break; + } + if (drm_lock_take(&dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT)) { + dev->lock.pid = priv->pid; + dev->lock.lock_time = jiffies; + atomic_inc(&dev->total_locks); + break; /* Got lock */ + } + /* Contention */ + atomic_inc(&dev->total_sleeps); + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (signal_pending(current)) { + retcode = -ERESTARTSYS; + break; } - spin_unlock(&dev->count_lock); - return i810_takedown(dev); } - spin_unlock(&dev->count_lock); + current->state = TASK_RUNNING; + remove_wait_queue(&dev->lock.lock_queue, &entry); + if(!retcode) { + i810_reclaim_buffers(dev, priv->pid); + drm_lock_free(dev, &dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT); + } + } + drm_fasync(-1, filp, 0); + + down(&dev->struct_sem); + if (priv->prev) priv->prev->next = priv->next; + else dev->file_first = priv->next; + if (priv->next) priv->next->prev = priv->prev; + else dev->file_last = priv->prev; + up(&dev->struct_sem); + + drm_free(priv, sizeof(*priv), DRM_MEM_FILES); + MOD_DEC_USE_COUNT; + atomic_inc(&dev->total_close); + spin_lock(&dev->count_lock); + if (!--dev->open_count) { + if (atomic_read(&dev->ioctl_count) || dev->blocked) { + DRM_ERROR("Device busy: %d %d\n", + atomic_read(&dev->ioctl_count), + dev->blocked); + spin_unlock(&dev->count_lock); + return -EBUSY; + } + spin_unlock(&dev->count_lock); + return i810_takedown(dev); } + spin_unlock(&dev->count_lock); return retcode; } @@ -566,8 +636,7 @@ int i810_unlock(struct inode *inode, struct file *filp, unsigned int cmd, atomic_inc(&dev->total_unlocks); if (_DRM_LOCK_IS_CONT(dev->lock.hw_lock->lock)) atomic_inc(&dev->total_contends); - drm_lock_transfer(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT); - i810_dma_schedule(dev, 1); + drm_lock_transfer(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT); if (!dev->context_flag) { if (drm_lock_free(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT)) { diff --git a/linux/i810_drv.h b/linux/i810_drv.h index 0f5f42bb6..1badd36b8 100644 --- a/linux/i810_drv.h +++ b/linux/i810_drv.h @@ -32,6 +32,31 @@ #ifndef _I810_DRV_H_ #define _I810_DRV_H_ +typedef struct _drm_i810_ring_buffer{ + int tail_mask; + unsigned long Start; + unsigned long End; + unsigned long Size; + u8 *virtual_start; + int head; + int tail; + int space; +} drm_i810_ring_buffer_t; + +typedef struct drm_i810_private { + int ring_map_idx; + int buffer_map_idx; + + drm_i810_ring_buffer_t ring; + drm_i810_sarea_t *sarea_priv; + + unsigned long hw_status_page; + unsigned long counter; + + atomic_t flush_done; + wait_queue_head_t flush_queue; /* Processes waiting until flush */ +} drm_i810_private_t; + /* i810_drv.c */ extern int i810_init(void); extern void i810_cleanup(void); @@ -54,8 +79,13 @@ extern int i810_control(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int i810_lock(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -extern void i810_dma_init(drm_device_t *dev); -extern void i810_dma_cleanup(drm_device_t *dev); +extern int i810_dma_init(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_flush_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern void i810_reclaim_buffers(drm_device_t *dev, pid_t pid); +extern int i810_getage(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); /* i810_bufs.c */ @@ -72,5 +102,103 @@ extern int i810_mapbufs(struct inode *inode, struct file *filp, extern int i810_addmap(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); + /* i810_context.c */ +extern int i810_resctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_addctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_modctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_getctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_switchctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_newctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_rmctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + +extern int i810_context_switch(drm_device_t *dev, int old, int new); +extern int i810_context_switch_complete(drm_device_t *dev, int new); + + + + +/* Copy the outstanding cliprects for every I810_DMA_VERTEX buffer. + * This can be fixed by emitting directly to the ringbuffer in the + * 'vertex_dma' ioctl. +*/ +typedef struct { + u32 *in_use; + int my_use_idx; +} drm_i810_buf_priv_t; + + +#define I810_DMA_GENERAL 0 +#define I810_DMA_VERTEX 1 +#define I810_DMA_DISCARD 2 /* not used */ + +#define I810_VERBOSE 0 + + +int i810_dma_vertex(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + +int i810_dma_general(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + + +#define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23)) +#define GFX_OP_BREAKPOINT_INTERRUPT ((0<<29)|(1<<23)) +#define CMD_REPORT_HEAD (7<<23) +#define CMD_STORE_DWORD_IDX ((0x21<<23) | 0x1) +#define CMD_OP_BATCH_BUFFER ((0x0<<29)|(0x30<<23)|0x1) + +#define INST_PARSER_CLIENT 0x00000000 +#define INST_OP_FLUSH 0x02000000 +#define INST_FLUSH_MAP_CACHE 0x00000001 + + +#define BB1_START_ADDR_MASK (~0x7) +#define BB1_PROTECTED (1<<0) +#define BB1_UNPROTECTED (0<<0) +#define BB2_END_ADDR_MASK (~0x7) + +#define I810REG_HWSTAM 0x02098 +#define I810REG_INT_IDENTITY_R 0x020a4 +#define I810REG_INT_MASK_R 0x020a8 +#define I810REG_INT_ENABLE_R 0x020a0 + +#define LP_RING 0x2030 +#define HP_RING 0x2040 +#define RING_TAIL 0x00 +#define TAIL_ADDR 0x000FFFF8 +#define RING_HEAD 0x04 +#define HEAD_WRAP_COUNT 0xFFE00000 +#define HEAD_WRAP_ONE 0x00200000 +#define HEAD_ADDR 0x001FFFFC +#define RING_START 0x08 +#define START_ADDR 0x00FFFFF8 +#define RING_LEN 0x0C +#define RING_NR_PAGES 0x000FF000 +#define RING_REPORT_MASK 0x00000006 +#define RING_REPORT_64K 0x00000002 +#define RING_REPORT_128K 0x00000004 +#define RING_NO_REPORT 0x00000000 +#define RING_VALID_MASK 0x00000001 +#define RING_VALID 0x00000001 +#define RING_INVALID 0x00000000 + +#define GFX_OP_SCISSOR ((0x3<<29)|(0x1c<<24)|(0x10<<19)) +#define SC_UPDATE_SCISSOR (0x1<<1) +#define SC_ENABLE_MASK (0x1<<0) +#define SC_ENABLE (0x1<<0) + +#define GFX_OP_SCISSOR_INFO ((0x3<<29)|(0x1d<<24)|(0x81<<16)|(0x1)) +#define SCI_YMIN_MASK (0xffff<<16) +#define SCI_XMIN_MASK (0xffff<<0) +#define SCI_YMAX_MASK (0xffff<<16) +#define SCI_XMAX_MASK (0xffff<<0) #endif + diff --git a/linux/memory.c b/linux/memory.c index a8a81abd8..559ac7391 100644 --- a/linux/memory.c +++ b/linux/memory.c @@ -44,21 +44,25 @@ static spinlock_t drm_mem_lock = SPIN_LOCK_UNLOCKED; static unsigned long drm_ram_available = 0; /* In pages */ static unsigned long drm_ram_used = 0; static drm_mem_stats_t drm_mem_stats[] = { - [DRM_MEM_DMA] = { "dmabufs" }, - [DRM_MEM_SAREA] = { "sareas" }, - [DRM_MEM_DRIVER] = { "driver" }, - [DRM_MEM_MAGIC] = { "magic" }, - [DRM_MEM_IOCTLS] = { "ioctltab" }, - [DRM_MEM_MAPS] = { "maplist" }, - [DRM_MEM_VMAS] = { "vmalist" }, - [DRM_MEM_BUFS] = { "buflist" }, - [DRM_MEM_SEGS] = { "seglist" }, - [DRM_MEM_PAGES] = { "pagelist" }, - [DRM_MEM_FILES] = { "files" }, - [DRM_MEM_QUEUES] = { "queues" }, - [DRM_MEM_CMDS] = { "commands" }, - [DRM_MEM_MAPPINGS] = { "mappings" }, - [DRM_MEM_BUFLISTS] = { "buflists" }, + [DRM_MEM_DMA] = { "dmabufs" }, + [DRM_MEM_SAREA] = { "sareas" }, + [DRM_MEM_DRIVER] = { "driver" }, + [DRM_MEM_MAGIC] = { "magic" }, + [DRM_MEM_IOCTLS] = { "ioctltab" }, + [DRM_MEM_MAPS] = { "maplist" }, + [DRM_MEM_VMAS] = { "vmalist" }, + [DRM_MEM_BUFS] = { "buflist" }, + [DRM_MEM_SEGS] = { "seglist" }, + [DRM_MEM_PAGES] = { "pagelist" }, + [DRM_MEM_FILES] = { "files" }, + [DRM_MEM_QUEUES] = { "queues" }, + [DRM_MEM_CMDS] = { "commands" }, + [DRM_MEM_MAPPINGS] = { "mappings" }, + [DRM_MEM_BUFLISTS] = { "buflists" }, + [DRM_MEM_AGPLISTS] = { "agplist" }, + [DRM_MEM_TOTALAGP] = { "totalagp" }, + [DRM_MEM_BOUNDAGP] = { "boundagp" }, + [DRM_MEM_CTXBITMAP] = { "ctxbitmap"}, { NULL, 0, } /* Last entry must be null */ }; @@ -324,3 +328,120 @@ void drm_ioremapfree(void *pt, unsigned long size) free_count, alloc_count); } } + +#ifdef DRM_AGP +agp_memory *drm_alloc_agp(int pages, u32 type) +{ + agp_memory *handle; + + if (!pages) { + DRM_MEM_ERROR(DRM_MEM_TOTALAGP, "Allocating 0 pages\n"); + return NULL; + } + + if (drm_agp.allocate_memory) { + if ((handle = (*drm_agp.allocate_memory)(pages, + type))) { + spin_lock(&drm_mem_lock); + ++drm_mem_stats[DRM_MEM_TOTALAGP].succeed_count; + drm_mem_stats[DRM_MEM_TOTALAGP].bytes_allocated + += pages << PAGE_SHIFT; + spin_unlock(&drm_mem_lock); + return handle; + } + } + spin_lock(&drm_mem_lock); + ++drm_mem_stats[DRM_MEM_TOTALAGP].fail_count; + spin_unlock(&drm_mem_lock); + return NULL; +} + +int drm_free_agp(agp_memory *handle, int pages) +{ + int alloc_count; + int free_count; + int retval = -EINVAL; + + if (!handle) { + DRM_MEM_ERROR(DRM_MEM_TOTALAGP, + "Attempt to free NULL AGP handle\n"); + return retval;; + } + + if (drm_agp.free_memory) { + (*drm_agp.free_memory)(handle); + spin_lock(&drm_mem_lock); + free_count = ++drm_mem_stats[DRM_MEM_TOTALAGP].free_count; + alloc_count = drm_mem_stats[DRM_MEM_TOTALAGP].succeed_count; + drm_mem_stats[DRM_MEM_TOTALAGP].bytes_freed + += pages << PAGE_SHIFT; + spin_unlock(&drm_mem_lock); + if (free_count > alloc_count) { + DRM_MEM_ERROR(DRM_MEM_TOTALAGP, + "Excess frees: %d frees, %d allocs\n", + free_count, alloc_count); + } + return 0; + } + return retval; +} + +int drm_bind_agp(agp_memory *handle, unsigned int start) +{ + int retcode = -EINVAL; + + DRM_DEBUG("drm_bind_agp called\n"); + if (!handle) { + DRM_MEM_ERROR(DRM_MEM_BOUNDAGP, + "Attempt to bind NULL AGP handle\n"); + return retcode; + } + + DRM_DEBUG("drm_agp.bind_memory : %p\n", drm_agp.bind_memory); + if (drm_agp.bind_memory) { + if (!(retcode = (*drm_agp.bind_memory)(handle, start))) { + spin_lock(&drm_mem_lock); + ++drm_mem_stats[DRM_MEM_BOUNDAGP].succeed_count; + drm_mem_stats[DRM_MEM_BOUNDAGP].bytes_allocated + += handle->page_count << PAGE_SHIFT; + spin_unlock(&drm_mem_lock); + DRM_DEBUG("drm_agp.bind_memory: retcode %d\n", retcode); + return retcode; + } + } + spin_lock(&drm_mem_lock); + ++drm_mem_stats[DRM_MEM_BOUNDAGP].fail_count; + spin_unlock(&drm_mem_lock); + return retcode; +} + +int drm_unbind_agp(agp_memory *handle) +{ + int alloc_count; + int free_count; + int retcode = -EINVAL; + + if (!handle) { + DRM_MEM_ERROR(DRM_MEM_BOUNDAGP, + "Attempt to unbind NULL AGP handle\n"); + return retcode; + } + + if (drm_agp.unbind_memory) { + int c = handle->page_count; + if ((retcode = (*drm_agp.unbind_memory)(handle))) + return retcode; + spin_lock(&drm_mem_lock); + free_count = ++drm_mem_stats[DRM_MEM_BOUNDAGP].free_count; + alloc_count = drm_mem_stats[DRM_MEM_BOUNDAGP].succeed_count; + drm_mem_stats[DRM_MEM_BOUNDAGP].bytes_freed += c << PAGE_SHIFT; + spin_unlock(&drm_mem_lock); + if (free_count > alloc_count) { + DRM_MEM_ERROR(DRM_MEM_BOUNDAGP, + "Excess frees: %d frees, %d allocs\n", + free_count, alloc_count); + } + } + return retcode; +} +#endif diff --git a/linux/mga_bufs.c b/linux/mga_bufs.c index 34f1112a6..3ce428b27 100644 --- a/linux/mga_bufs.c +++ b/linux/mga_bufs.c @@ -33,169 +33,168 @@ #define __NO_VERSION__ #include "drmP.h" #include "mga_drv.h" -#include "mga_dma.h" #include "linux/un.h" int mga_addbufs_agp(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_device_dma_t *dma = dev->dma; - drm_buf_desc_t request; - drm_buf_entry_t *entry; - drm_buf_t *buf; - unsigned long offset; - unsigned long agp_offset; - int count; - int order; - int size; - int alignment; - int page_order; - int total; - int byte_count; - int i; - - if (!dma) return -EINVAL; - - copy_from_user_ret(&request, - (drm_buf_desc_t *)arg, - sizeof(request), - -EFAULT); - - count = request.count; - order = drm_order(request.size); - size = 1 << order; - agp_offset = request.agp_start; - alignment = (request.flags & _DRM_PAGE_ALIGN) ? PAGE_ALIGN(size) :size; - page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; - total = PAGE_SIZE << page_order; - byte_count = 0; - - DRM_DEBUG("count: %d\n", count); - DRM_DEBUG("order: %d\n", order); - DRM_DEBUG("size: %d\n", size); - DRM_DEBUG("agp_offset: %d\n", agp_offset); - DRM_DEBUG("alignment: %d\n", alignment); - DRM_DEBUG("page_order: %d\n", page_order); - DRM_DEBUG("total: %d\n", total); - DRM_DEBUG("byte_count: %d\n", byte_count); - - if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL; - if (dev->queue_count) return -EBUSY; /* Not while in use */ - spin_lock(&dev->count_lock); - if (dev->buf_use) { - spin_unlock(&dev->count_lock); - return -EBUSY; - } - atomic_inc(&dev->buf_alloc); - spin_unlock(&dev->count_lock); + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_device_dma_t *dma = dev->dma; + drm_buf_desc_t request; + drm_buf_entry_t *entry; + drm_buf_t *buf; + unsigned long offset; + unsigned long agp_offset; + int count; + int order; + int size; + int alignment; + int page_order; + int total; + int byte_count; + int i; + + if (!dma) return -EINVAL; + + copy_from_user_ret(&request, + (drm_buf_desc_t *)arg, + sizeof(request), + -EFAULT); + + count = request.count; + order = drm_order(request.size); + size = 1 << order; + agp_offset = request.agp_start; + alignment = (request.flags & _DRM_PAGE_ALIGN) ? PAGE_ALIGN(size) :size; + page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; + total = PAGE_SIZE << page_order; + byte_count = 0; + + DRM_DEBUG("count: %d\n", count); + DRM_DEBUG("order: %d\n", order); + DRM_DEBUG("size: %d\n", size); + DRM_DEBUG("agp_offset: %ld\n", agp_offset); + DRM_DEBUG("alignment: %d\n", alignment); + DRM_DEBUG("page_order: %d\n", page_order); + DRM_DEBUG("total: %d\n", total); + DRM_DEBUG("byte_count: %d\n", byte_count); + + if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL; + if (dev->queue_count) return -EBUSY; /* Not while in use */ + spin_lock(&dev->count_lock); + if (dev->buf_use) { + spin_unlock(&dev->count_lock); + return -EBUSY; + } + atomic_inc(&dev->buf_alloc); + spin_unlock(&dev->count_lock); - down(&dev->struct_sem); - entry = &dma->bufs[order]; - if (entry->buf_count) { - up(&dev->struct_sem); - atomic_dec(&dev->buf_alloc); - return -ENOMEM; /* May only call once for each order */ - } + down(&dev->struct_sem); + entry = &dma->bufs[order]; + if (entry->buf_count) { + up(&dev->struct_sem); + 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) { - up(&dev->struct_sem); - atomic_dec(&dev->buf_alloc); - return -ENOMEM; - } - memset(entry->buflist, 0, count * sizeof(*entry->buflist)); + entry->buflist = drm_alloc(count * sizeof(*entry->buflist), + DRM_MEM_BUFS); + if (!entry->buflist) { + up(&dev->struct_sem); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; + } + memset(entry->buflist, 0, count * sizeof(*entry->buflist)); - entry->buf_size = size; - entry->page_order = page_order; - offset = 0; + entry->buf_size = size; + entry->page_order = page_order; + offset = 0; - while(entry->buf_count < count) { - buf = &entry->buflist[entry->buf_count]; - buf->idx = dma->buf_count + entry->buf_count; - buf->total = alignment; - buf->order = order; - buf->used = 0; - - DRM_DEBUG("offset : %d\n", offset); - - buf->offset = offset; /* Hrm */ - buf->bus_address = dev->agp->base + agp_offset + offset; - buf->address = (void *)(agp_offset + offset + dev->agp->base); - buf->next = NULL; - buf->waiting = 0; - buf->pending = 0; - init_waitqueue_head(&buf->dma_wait); - buf->pid = 0; - - buf->dev_private = drm_alloc(sizeof(drm_mga_buf_priv_t), DRM_MEM_BUFS); - buf->dev_priv_size = sizeof(drm_mga_buf_priv_t); + while(entry->buf_count < count) { + buf = &entry->buflist[entry->buf_count]; + buf->idx = dma->buf_count + entry->buf_count; + buf->total = alignment; + buf->order = order; + buf->used = 0; + + DRM_DEBUG("offset : %ld\n", offset); + + buf->offset = offset; /* Hrm */ + buf->bus_address = dev->agp->base + agp_offset + offset; + buf->address = (void *)(agp_offset + offset + dev->agp->base); + buf->next = NULL; + buf->waiting = 0; + buf->pending = 0; + init_waitqueue_head(&buf->dma_wait); + buf->pid = 0; + + buf->dev_private = drm_alloc(sizeof(drm_mga_buf_priv_t), DRM_MEM_BUFS); + buf->dev_priv_size = sizeof(drm_mga_buf_priv_t); #if DRM_DMA_HISTOGRAM - buf->time_queued = 0; - buf->time_dispatched = 0; - buf->time_completed = 0; - buf->time_freed = 0; + buf->time_queued = 0; + buf->time_dispatched = 0; + buf->time_completed = 0; + buf->time_freed = 0; #endif - offset = offset + alignment; - entry->buf_count++; - byte_count += PAGE_SIZE << page_order; + offset = offset + alignment; + entry->buf_count++; + byte_count += PAGE_SIZE << page_order; - DRM_DEBUG("buffer %d @ %p\n", - entry->buf_count, buf->address); - } + DRM_DEBUG("buffer %d @ %p\n", + entry->buf_count, buf->address); + } - dma->buflist = drm_realloc(dma->buflist, - dma->buf_count * sizeof(*dma->buflist), - (dma->buf_count + entry->buf_count) - * sizeof(*dma->buflist), - DRM_MEM_BUFS); - for (i = dma->buf_count; i < dma->buf_count + entry->buf_count; i++) - dma->buflist[i] = &entry->buflist[i - dma->buf_count]; + dma->buflist = drm_realloc(dma->buflist, + dma->buf_count * sizeof(*dma->buflist), + (dma->buf_count + entry->buf_count) + * sizeof(*dma->buflist), + DRM_MEM_BUFS); + for (i = dma->buf_count; i < dma->buf_count + entry->buf_count; i++) + dma->buflist[i] = &entry->buflist[i - dma->buf_count]; - dma->buf_count += entry->buf_count; + dma->buf_count += entry->buf_count; - DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count); + DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count); - dma->byte_count += byte_count; + dma->byte_count += byte_count; - DRM_DEBUG("entry->buf_count : %d\n", entry->buf_count); + DRM_DEBUG("entry->buf_count : %d\n", entry->buf_count); - drm_freelist_create(&entry->freelist, entry->buf_count); - for (i = 0; i < entry->buf_count; i++) { - drm_freelist_put(dev, &entry->freelist, &entry->buflist[i]); - } + drm_freelist_create(&entry->freelist, entry->buf_count); + for (i = 0; i < entry->buf_count; i++) { + drm_freelist_put(dev, &entry->freelist, &entry->buflist[i]); + } - up(&dev->struct_sem); + up(&dev->struct_sem); - request.count = entry->buf_count; - request.size = size; + request.count = entry->buf_count; + request.size = size; - copy_to_user_ret((drm_buf_desc_t *)arg, - &request, - sizeof(request), - -EFAULT); + copy_to_user_ret((drm_buf_desc_t *)arg, + &request, + sizeof(request), + -EFAULT); - atomic_dec(&dev->buf_alloc); + atomic_dec(&dev->buf_alloc); - DRM_DEBUG("count: %d\n", count); - DRM_DEBUG("order: %d\n", order); - DRM_DEBUG("size: %d\n", size); - DRM_DEBUG("agp_offset: %d\n", agp_offset); - DRM_DEBUG("alignment: %d\n", alignment); - DRM_DEBUG("page_order: %d\n", page_order); - DRM_DEBUG("total: %d\n", total); - DRM_DEBUG("byte_count: %d\n", byte_count); + DRM_DEBUG("count: %d\n", count); + DRM_DEBUG("order: %d\n", order); + DRM_DEBUG("size: %d\n", size); + DRM_DEBUG("agp_offset: %ld\n", agp_offset); + DRM_DEBUG("alignment: %d\n", alignment); + DRM_DEBUG("page_order: %d\n", page_order); + DRM_DEBUG("total: %d\n", total); + DRM_DEBUG("byte_count: %d\n", byte_count); - dma->flags = _DRM_DMA_USE_AGP; + dma->flags = _DRM_DMA_USE_AGP; - DRM_DEBUG("dma->flags : %lx\n", dma->flags); + DRM_DEBUG("dma->flags : %x\n", dma->flags); - return 0; + return 0; } int mga_addbufs_pci(struct inode *inode, struct file *filp, unsigned int cmd, @@ -362,17 +361,17 @@ int mga_addbufs_pci(struct inode *inode, struct file *filp, unsigned int cmd, int mga_addbufs(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { - drm_buf_desc_t request; + drm_buf_desc_t request; - copy_from_user_ret(&request, - (drm_buf_desc_t *)arg, - sizeof(request), - -EFAULT); + copy_from_user_ret(&request, + (drm_buf_desc_t *)arg, + sizeof(request), + -EFAULT); - if(request.flags & _DRM_AGP_BUFFER) - return mga_addbufs_agp(inode, filp, cmd, arg); - else - return mga_addbufs_pci(inode, filp, cmd, arg); + if(request.flags & _DRM_AGP_BUFFER) + return mga_addbufs_agp(inode, filp, cmd, arg); + else + return mga_addbufs_pci(inode, filp, cmd, arg); } int mga_infobufs(struct inode *inode, struct file *filp, unsigned int cmd, @@ -546,7 +545,7 @@ int mga_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd, spin_lock(&dev->count_lock); if (atomic_read(&dev->buf_alloc)) { spin_unlock(&dev->count_lock); - DRM_DEBUG("Buzy\n"); + DRM_DEBUG("Busy\n"); return -EBUSY; } ++dev->buf_use; /* Can't allocate more after this call */ @@ -558,79 +557,84 @@ int mga_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd, -EFAULT); DRM_DEBUG("mga_mapbufs\n"); - DRM_DEBUG("dma->flags : %lx\n", dma->flags); + DRM_DEBUG("dma->flags : %x\n", dma->flags); - if (request.count >= dma->buf_count) { - if(dma->flags & _DRM_DMA_USE_AGP) { - drm_mga_private_t *dev_priv = dev->dev_private; - drm_map_t *map = NULL; + if (request.count >= dma->buf_count) { + if(dma->flags & _DRM_DMA_USE_AGP) { + drm_mga_private_t *dev_priv = dev->dev_private; + drm_map_t *map = NULL; - map = dev->maplist[dev_priv->buffer_map_idx]; - if (!map) { - DRM_DEBUG("map is null\n"); - retcode = -EINVAL; - goto done; - } - - DRM_DEBUG("map->offset : %lx\n", map->offset); - DRM_DEBUG("map->size : %lx\n", map->size); - DRM_DEBUG("map->type : %d\n", map->type); - DRM_DEBUG("map->flags : %x\n", map->flags); - DRM_DEBUG("map->handle : %lx\n", map->handle); - DRM_DEBUG("map->mtrr : %d\n", map->mtrr); - - virtual = do_mmap(filp, 0, map->size, PROT_READ|PROT_WRITE, - MAP_SHARED, (unsigned long)map->offset); - } else { - virtual = do_mmap(filp, 0, dma->byte_count, - PROT_READ|PROT_WRITE, MAP_SHARED, 0); - } - if (virtual > -1024UL) { - /* Real error */ - DRM_DEBUG("mmap error\n"); - retcode = (signed long)virtual; - goto done; - } - request.virtual = (void *)virtual; + map = dev->maplist[dev_priv->buffer_map_idx]; + if (!map) { + DRM_DEBUG("map is null\n"); + retcode = -EINVAL; + goto done; + } + + DRM_DEBUG("map->offset : %lx\n", map->offset); + DRM_DEBUG("map->size : %lx\n", map->size); + DRM_DEBUG("map->type : %d\n", map->type); + DRM_DEBUG("map->flags : %x\n", map->flags); + DRM_DEBUG("map->handle : %p\n", map->handle); + DRM_DEBUG("map->mtrr : %d\n", map->mtrr); + down(¤t->mm->mmap_sem); + virtual = do_mmap(filp, 0, map->size, + PROT_READ|PROT_WRITE, + MAP_SHARED, + (unsigned long)map->offset); + up(¤t->mm->mmap_sem); + } else { + down(¤t->mm->mmap_sem); + virtual = do_mmap(filp, 0, dma->byte_count, + PROT_READ|PROT_WRITE, MAP_SHARED, 0); + up(¤t->mm->mmap_sem); + } + if (virtual > -1024UL) { + /* Real error */ + DRM_DEBUG("mmap error\n"); + retcode = (signed long)virtual; + goto done; + } + request.virtual = (void *)virtual; - for (i = 0; i < dma->buf_count; i++) { - if (copy_to_user(&request.list[i].idx, - &dma->buflist[i]->idx, - sizeof(request.list[0].idx))) { - retcode = -EFAULT; - goto done; - } - if (copy_to_user(&request.list[i].total, - &dma->buflist[i]->total, - sizeof(request.list[0].total))) { - retcode = -EFAULT; - goto done; - } - if (copy_to_user(&request.list[i].used, - &zero, - sizeof(zero))) { - retcode = -EFAULT; - goto done; - } - address = virtual + dma->buflist[i]->offset; - if (copy_to_user(&request.list[i].address, - &address, - sizeof(address))) { - retcode = -EFAULT; - goto done; - } - } - } - done: - request.count = dma->buf_count; - DRM_DEBUG("%d buffers, retcode = %d\n", request.count, retcode); + for (i = 0; i < dma->buf_count; i++) { + if (copy_to_user(&request.list[i].idx, + &dma->buflist[i]->idx, + sizeof(request.list[0].idx))) { + retcode = -EFAULT; + goto done; + } + if (copy_to_user(&request.list[i].total, + &dma->buflist[i]->total, + sizeof(request.list[0].total))) { + retcode = -EFAULT; + goto done; + } + if (copy_to_user(&request.list[i].used, + &zero, + sizeof(zero))) { + retcode = -EFAULT; + goto done; + } + address = virtual + dma->buflist[i]->offset; + if (copy_to_user(&request.list[i].address, + &address, + sizeof(address))) { + retcode = -EFAULT; + goto done; + } + } + } + done: + request.count = dma->buf_count; + DRM_DEBUG("%d buffers, retcode = %d\n", request.count, retcode); - copy_to_user_ret((drm_buf_map_t *)arg, - &request, - sizeof(request), - -EFAULT); + copy_to_user_ret((drm_buf_map_t *)arg, + &request, + sizeof(request), + -EFAULT); - DRM_DEBUG("retcode : %d\n", retcode); + DRM_DEBUG("retcode : %d\n", retcode); - return retcode; + return retcode; } diff --git a/linux/mga_clear.c b/linux/mga_clear.c deleted file mode 100644 index 05895415e..000000000 --- a/linux/mga_clear.c +++ /dev/null @@ -1,417 +0,0 @@ -/* mga_state.c -- State support for mga g200/g400 -*- linux-c -*- - * - * Created: February 2000 by keithw@precisioninsight.com - * - * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. - * 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: - * Keith Whitwell - * - */ - -#define __NO_VERSION__ -#include "drmP.h" -#include "mga_drv.h" -#include "mgareg_flags.h" -#include "mga_dma.h" -#include "mga_state.h" - -#define MGA_CLEAR_CMD (DC_opcod_trap | DC_arzero_enable | \ - DC_sgnzero_enable | DC_shftzero_enable | \ - (0xC << DC_bop_SHIFT) | DC_clipdis_enable | \ - DC_solid_enable | DC_transc_enable) - - -#define MGA_COPY_CMD (DC_opcod_bitblt | DC_atype_rpl | DC_linear_xy | \ - DC_solid_disable | DC_arzero_disable | \ - DC_sgnzero_enable | DC_shftzero_enable | \ - (0xC << DC_bop_SHIFT) | DC_bltmod_bfcol | \ - DC_pattern_disable | DC_transc_disable | \ - DC_clipdis_enable) \ - - - -/* Build and queue a TT_GENERAL secondary buffer to do the clears. - * With Jeff's ringbuffer idea, it might make sense if there are only - * one or two cliprects to emit straight to the primary buffer. - */ -static int mgaClearBuffers(drm_device_t *dev, - int clear_color, - int clear_depth, - int flags) -{ - int cmd, i; - drm_device_dma_t *dma = dev->dma; - drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; - drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; - xf86drmClipRectRec *pbox = sarea_priv->boxes; - int nbox = sarea_priv->nbox; - drm_buf_t *buf; - drm_dma_t d; - int order = 10; /* ??? what orders do we have ???*/ - DMALOCALS; - - - if (!nbox) - return -EINVAL; - - if ( dev_priv->sgram ) - cmd = MGA_CLEAR_CMD | DC_atype_blk; - else - cmd = MGA_CLEAR_CMD | DC_atype_rstr; - - buf = drm_freelist_get(&dma->bufs[order].freelist, _DRM_DMA_WAIT); - - - DMAGETPTR( buf ); - - for (i = 0 ; i < nbox ; i++) { - unsigned int height = pbox[i].y2 - pbox[i].y1; - - /* Is it necessary to be this paranoid? I don't think so. - if (pbox[i].x1 > dev_priv->width) continue; - if (pbox[i].y1 > dev_priv->height) continue; - if (pbox[i].x2 > dev_priv->width) continue; - if (pbox[i].y2 > dev_priv->height) continue; - if (pbox[i].x2 <= pbox[i].x1) continue; - if (pbox[i].y2 <= pbox[i].x1) continue; - */ - - DMAOUTREG(MGAREG_YDSTLEN, (pbox[i].y1<<16)|height); - DMAOUTREG(MGAREG_FXBNDRY, (pbox[i].x2<<16)|pbox[i].x1); - - if ( flags & MGA_CLEAR_FRONT ) { - DMAOUTREG(MGAREG_FCOL, clear_color); - DMAOUTREG(MGAREG_DSTORG, dev_priv->frontOrg); - DMAOUTREG(MGAREG_DWGCTL+MGAREG_MGA_EXEC, cmd ); - } - - if ( flags & MGA_CLEAR_BACK ) { - DMAOUTREG(MGAREG_FCOL, clear_color); - DMAOUTREG(MGAREG_DSTORG, dev_priv->backOrg); - DMAOUTREG(MGAREG_DWGCTL+MGAREG_MGA_EXEC, cmd ); - } - - if ( flags & MGA_CLEAR_DEPTH ) - { - DMAOUTREG(MGAREG_FCOL, clear_depth); - DMAOUTREG(MGAREG_DSTORG, dev_priv->depthOrg); - DMAOUTREG(MGAREG_DWGCTL+MGAREG_MGA_EXEC, cmd ); - } - } - - DMAADVANCE( buf ); - - /* Make sure we restore the 3D state next time. - */ - sarea_priv->dirty |= MGASAREA_NEW_CONTEXT; - - ((drm_mga_buf_priv_t *)buf->dev_private)->dma_type = MGA_DMA_GENERAL; - - d.context = DRM_KERNEL_CONTEXT; - d.send_count = 1; - d.send_indices = &buf->idx; - d.send_sizes = &buf->used; - d.flags = 0; - d.request_count = 0; - d.request_size = 0; - d.request_indices = NULL; - d.request_sizes = NULL; - d.granted_count = 0; - - atomic_inc(&dev_priv->pending_bufs); - if((drm_dma_enqueue(dev, &d)) != 0) - atomic_dec(&dev_priv->pending_bufs); - mga_dma_schedule(dev, 1); - return 0; -} - -int mgaSwapBuffers(drm_device_t *dev, int flags) -{ - drm_device_dma_t *dma = dev->dma; - drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; - drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; - xf86drmClipRectRec *pbox = sarea_priv->boxes; - int nbox = sarea_priv->nbox; - drm_buf_t *buf; - drm_dma_t d; - int order = 10; /* ??? */ - int i; - DMALOCALS; - - if (!nbox) - return -EINVAL; - - buf = drm_freelist_get(&dma->bufs[order].freelist, _DRM_DMA_WAIT); - - DMAGETPTR(buf); - - DMAOUTREG(MGAREG_DSTORG, dev_priv->frontOrg); - DMAOUTREG(MGAREG_MACCESS, dev_priv->mAccess); - DMAOUTREG(MGAREG_SRCORG, dev_priv->backOrg); - DMAOUTREG(MGAREG_AR5, dev_priv->stride); /* unnecessary? */ - DMAOUTREG(MGAREG_DWGCTL, MGA_COPY_CMD); - - for (i = 0 ; i < nbox; i++) { - unsigned int h = pbox[i].y2 - pbox[i].y1; - unsigned int start = pbox[i].y1 * dev_priv->stride; - - /* - if (pbox[i].x1 > dev_priv->width) continue; - if (pbox[i].y1 > dev_priv->height) continue; - if (pbox[i].x2 > dev_priv->width) continue; - if (pbox[i].y2 > dev_priv->height) continue; - if (pbox[i].x2 <= pbox[i].x1) continue; - if (pbox[i].y2 <= pbox[i].x1) continue; - */ - - DMAOUTREG(MGAREG_AR0, start + pbox[i].x2 - 1); - DMAOUTREG(MGAREG_AR3, start + pbox[i].x1); - DMAOUTREG(MGAREG_FXBNDRY, pbox[i].x1|((pbox[i].x2 - 1)<<16)); - DMAOUTREG(MGAREG_YDSTLEN+MGAREG_MGA_EXEC, (pbox[i].y1<<16)|h); - } - - DMAOUTREG(MGAREG_SRCORG, 0); - DMAADVANCE( buf ); - - /* Make sure we restore the 3D state next time. - */ - sarea_priv->dirty |= MGASAREA_NEW_CONTEXT; - - ((drm_mga_buf_priv_t *)buf->dev_private)->dma_type = MGA_DMA_GENERAL; - - d.context = DRM_KERNEL_CONTEXT; - d.send_count = 1; - d.send_indices = &buf->idx; - d.send_sizes = &buf->used; - d.flags = 0; - d.request_count = 0; - d.request_size = 0; - d.request_indices = NULL; - d.request_sizes = NULL; - d.granted_count = 0; - - atomic_inc(&dev_priv->pending_bufs); - if((drm_dma_enqueue(dev, &d)) != 0) - atomic_dec(&dev_priv->pending_bufs); - mga_dma_schedule(dev, 1); - return 0; -} - - -static int mgaIload(drm_device_t *dev, drm_mga_iload_t *args) -{ - drm_device_dma_t *dma = dev->dma; - drm_buf_t *buf = dma->buflist[ args->idx ]; - drm_mga_buf_priv_t *buf_priv = (drm_mga_buf_priv_t *)buf->dev_private; - drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; - drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; - drm_dma_t d; - int pixperdword; - - buf_priv->dma_type = MGA_DMA_ILOAD; - buf_priv->boxes[0].y1 = args->texture.y1; - buf_priv->boxes[0].y2 = args->texture.y2; - buf_priv->boxes[0].x1 = args->texture.x1; - buf_priv->boxes[0].x2 = args->texture.x2; - buf_priv->ContextState[MGA_CTXREG_DSTORG] = args->destOrg; - buf_priv->ContextState[MGA_CTXREG_MACCESS] = args->mAccess; - buf_priv->ServerState[MGA_2DREG_PITCH] = args->pitch; - buf_priv->nbox = 1; - sarea_priv->dirty |= (MGASAREA_NEW_CONTEXT | MGASAREA_NEW_2D); - switch((args->mAccess & 0x00000003)) { - case 0: - pixperdword = 4; - break; - case 1: - pixperdword = 2; - break; - case 2: - pixperdword = 1; - break; - default: - DRM_ERROR("Invalid maccess value passed" - " to mgaIload\n"); - return -EINVAL; - } - buf->used = ((args->texture.y2 - args->texture.y1) * - (args->texture.x2 - args->texture.x1) / - pixperdword); - DRM_DEBUG("buf->used : %d\n", buf->used); - d.context = DRM_KERNEL_CONTEXT; - d.send_count = 1; - d.send_indices = &buf->idx; - d.send_sizes = &buf->used; - d.flags = 0; - d.request_count = 0; - d.request_size = 0; - d.request_indices = NULL; - d.request_sizes = NULL; - d.granted_count = 0; - - atomic_inc(&dev_priv->pending_bufs); - if((drm_dma_enqueue(dev, &d)) != 0) - atomic_dec(&dev_priv->pending_bufs); - mga_dma_schedule(dev, 1); - - return 0; -} - - -/* Necessary? Not necessary?? - */ -static int check_lock(void) -{ - return 1; -} - -int mga_clear_bufs(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_mga_clear_t clear; - int retcode; - - copy_from_user_ret(&clear, (drm_mga_clear_t *)arg, - sizeof(clear), -EFAULT); - -/* if (!check_lock( dev )) */ -/* return -EIEIO; */ - - retcode = mgaClearBuffers(dev, clear.clear_color, - clear.clear_depth, - clear.flags); - - return retcode; -} - -int mga_swap_bufs(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_mga_swap_t swap; - int retcode = 0; - -/* if (!check_lock( dev )) */ -/* return -EIEIO; */ - - copy_from_user_ret(&swap, (drm_mga_swap_t *)arg, - sizeof(swap), -EFAULT); - - retcode = mgaSwapBuffers(dev, swap.flags); - - return retcode; -} - -int mga_iload(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_mga_iload_t iload; - int retcode = 0; - -/* if (!check_lock( dev )) */ -/* return -EIEIO; */ - - copy_from_user_ret(&iload, (drm_mga_iload_t *)arg, - sizeof(iload), -EFAULT); - - retcode = mgaIload(dev, &iload); - - return retcode; -} - - -int mga_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_device_dma_t *dma = dev->dma; - int retcode = 0; - drm_dma_t d; - - copy_from_user_ret(&d, (drm_dma_t *)arg, sizeof(d), -EFAULT); - DRM_DEBUG("%d %d: %d send, %d req\n", - current->pid, d.context, d.send_count, d.request_count); - - /* Per-context queues are unworkable if you are trying to do - * state management from the client. - */ - d.context = DRM_KERNEL_CONTEXT; - d.flags &= ~_DRM_DMA_WHILE_LOCKED; - - /* Maybe multiple buffers is useful for iload... - * But this ioctl is only for *despatching* vertex data... - */ - if (d.send_count < 0 || d.send_count > 1) { - DRM_ERROR("Process %d trying to send %d buffers (max 1)\n", - current->pid, d.send_count); - return -EINVAL; - } - - - /* But it *is* used to request buffers for all types of dma: - */ - 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 (d.send_count) { - int idx = d.send_indices[0]; - drm_mga_buf_priv_t *buf_priv = dma->buflist[ idx ]->dev_private; - drm_mga_private_t *dev_priv = dev->dev_private; - - buf_priv->dma_type = MGA_DMA_VERTEX; - -/* if (!check_lock( dev )) */ -/* return -EIEIO; */ - - /* Snapshot the relevent bits of the sarea... - */ - mgaCopyAndVerifyState( dev_priv, buf_priv ); - - atomic_inc(&dev_priv->pending_bufs); - retcode = drm_dma_enqueue(dev, &d); - if(retcode != 0) - atomic_dec(&dev_priv->pending_bufs); - mga_dma_schedule(dev, 1); - } - - d.granted_count = 0; - - if (!retcode && d.request_count) { - retcode = drm_dma_get_buffers(dev, &d); - } - - DRM_DEBUG("%d returning, granted = %d\n", - current->pid, d.granted_count); - copy_to_user_ret((drm_dma_t *)arg, &d, sizeof(d), -EFAULT); - - return retcode; -} diff --git a/linux/mga_context.c b/linux/mga_context.c index fb0d336fa..2459b35bb 100644 --- a/linux/mga_context.c +++ b/linux/mga_context.c @@ -38,7 +38,7 @@ static int mga_alloc_queue(drm_device_t *dev) { int temp = drm_ctxbitmap_next(dev); - printk("mga_alloc_queue: %d\n", temp); + DRM_DEBUG("mga_alloc_queue: %d\n", temp); return temp; } @@ -57,7 +57,7 @@ int mga_context_switch(drm_device_t *dev, int old, int new) dev->ctx_start = get_cycles(); #endif - printk("Context switch from %d to %d\n", old, new); + DRM_DEBUG("Context switch from %d to %d\n", old, new); if (new == dev->last_context) { clear_bit(0, &dev->context_flag); @@ -104,7 +104,7 @@ int mga_resctx(struct inode *inode, struct file *filp, unsigned int cmd, drm_ctx_t ctx; int i; - printk("%d\n", DRM_RESERVED_CONTEXTS); + DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS); copy_from_user_ret(&res, (drm_ctx_res_t *)arg, sizeof(res), -EFAULT); if (res.count >= DRM_RESERVED_CONTEXTS) { memset(&ctx, 0, sizeof(ctx)); @@ -134,11 +134,11 @@ int mga_addctx(struct inode *inode, struct file *filp, unsigned int cmd, ctx.handle = mga_alloc_queue(dev); } if (ctx.handle == -1) { - printk("Not enough free contexts.\n"); + DRM_DEBUG("Not enough free contexts.\n"); /* Should this return -EBUSY instead? */ return -ENOMEM; } - printk("%d\n", ctx.handle); + DRM_DEBUG("%d\n", ctx.handle); copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT); return 0; } @@ -170,7 +170,7 @@ int mga_switchctx(struct inode *inode, struct file *filp, unsigned int cmd, drm_ctx_t ctx; copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); - printk("%d\n", ctx.handle); + DRM_DEBUG("%d\n", ctx.handle); return mga_context_switch(dev, dev->last_context, ctx.handle); } @@ -182,7 +182,7 @@ int mga_newctx(struct inode *inode, struct file *filp, unsigned int cmd, drm_ctx_t ctx; copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); - printk("%d\n", ctx.handle); + DRM_DEBUG("%d\n", ctx.handle); mga_context_switch_complete(dev, ctx.handle); return 0; @@ -194,51 +194,11 @@ int mga_rmctx(struct inode *inode, struct file *filp, unsigned int cmd, drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; drm_ctx_t ctx; - drm_queue_t *q; - drm_buf_t *buf; copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); - printk("%d\n", ctx.handle); - if(ctx.handle == DRM_KERNEL_CONTEXT) { - q = dev->queuelist[ctx.handle]; - atomic_inc(&q->use_count); - if (atomic_read(&q->use_count) == 1) { - /* No longer in use */ - atomic_dec(&q->use_count); - return -EINVAL; - } - atomic_inc(&q->finalization); /* Mark queue in finalization state */ - atomic_sub(2, &q->use_count); - /* Mark queue as unused (pending finalization) */ - - while (test_and_set_bit(0, &dev->interrupt_flag)) { - printk("Calling schedule from rmctx\n"); - schedule(); - if (signal_pending(current)) { - clear_bit(0, &dev->interrupt_flag); - return -EINTR; - } - } - - /* Remove queued buffers */ - while ((buf = drm_waitlist_get(&q->waitlist))) { - drm_free_buffer(dev, buf); - } - clear_bit(0, &dev->interrupt_flag); - - /* Wakeup blocked processes */ - wake_up_interruptible(&q->read_queue); - wake_up_interruptible(&q->write_queue); - wake_up_interruptible(&q->flush_queue); - - /* Finalization over. Queue is made - available when both use_count and - finalization become 0, which won't - happen until all the waiting processes - stop waiting. */ - atomic_dec(&q->finalization); - } else { - drm_ctxbitmap_free(dev, ctx.handle); + DRM_DEBUG("%d\n", ctx.handle); + if(ctx.handle != DRM_KERNEL_CONTEXT) { + drm_ctxbitmap_free(dev, ctx.handle); } return 0; diff --git a/linux/mga_dma.c b/linux/mga_dma.c index 2e24e5b48..59cbad6b4 100644 --- a/linux/mga_dma.c +++ b/linux/mga_dma.c @@ -25,17 +25,15 @@ * * Authors: Rickard E. (Rik) Faith * Jeff Hartmann + * Keith Whitwell * - * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/mga_dma.c,v 1.1 2000/02/11 17:26:07 dawes Exp $ + * $XFree86$ * */ #define __NO_VERSION__ #include "drmP.h" #include "mga_drv.h" -#include "mgareg_flags.h" -#include "mga_dma.h" -#include "mga_state.h" #include /* For task queue support */ @@ -48,643 +46,599 @@ #define MGA_WRITE(reg,val) do { MGA_DEREF(reg) = val; } while (0) #define PDEA_pagpxfer_enable 0x2 -#define MGA_SYNC_TAG 0x423f4200 -typedef enum { - TT_GENERAL, - TT_BLIT, - TT_VECTOR, - TT_VERTEX -} transferType_t; +static int mga_flush_queue(drm_device_t *dev); +static unsigned long mga_alloc_page(drm_device_t *dev) +{ + unsigned long address; + + address = __get_free_page(GFP_KERNEL); + if(address == 0UL) { + return 0; + } + atomic_inc(&mem_map[MAP_NR((void *) address)].count); + set_bit(PG_locked, &mem_map[MAP_NR((void *) address)].flags); + + return address; +} + +static void mga_free_page(drm_device_t *dev, unsigned long page) +{ + if(page == 0UL) { + return; + } + atomic_dec(&mem_map[MAP_NR((void *) page)].count); + clear_bit(PG_locked, &mem_map[MAP_NR((void *) page)].flags); + wake_up(&mem_map[MAP_NR((void *) page)].wait); + free_page(page); + return; +} static void mga_delay(void) { return; } -int mga_dma_cleanup(drm_device_t *dev) +static void mga_flush_write_combine(void) { - if(dev->dev_private) { - drm_mga_private_t *dev_priv = - (drm_mga_private_t *) dev->dev_private; - - if(dev_priv->ioremap) { - int temp = (dev_priv->warp_ucode_size + - dev_priv->primary_size + - PAGE_SIZE - 1) / PAGE_SIZE * PAGE_SIZE; - - drm_ioremapfree((void *) dev_priv->ioremap, temp); - } - - drm_free(dev->dev_private, sizeof(drm_mga_private_t), - DRM_MEM_DRIVER); - dev->dev_private = NULL; - } - - return 0; + int xchangeDummy; + __asm__ volatile(" push %%eax ; xchg %%eax, %0 ; pop %%eax" : : "m" (xchangeDummy)); + __asm__ volatile(" push %%eax ; push %%ebx ; push %%ecx ; push %%edx ;" + " movl $0,%%eax ; cpuid ; pop %%edx ; pop %%ecx ; pop %%ebx ;" + " pop %%eax" : /* no outputs */ : /* no inputs */ ); } -static int mga_alloc_kernel_queue(drm_device_t *dev) +/* These are two age tags that will never be sent to + * the hardware */ +#define MGA_BUF_USED 0xffffffff +#define MGA_BUF_FREE 0 + +static void mga_freelist_debug(drm_mga_freelist_t *item) { - drm_queue_t *queue = NULL; - /* Allocate a new queue */ - down(&dev->struct_sem); - - if(dev->queue_count != 0) { - /* Reseting the kernel context here is not - * a race, since it can only happen when that - * queue is empty. - */ - queue = dev->queuelist[DRM_KERNEL_CONTEXT]; - printk("Kernel queue already allocated\n"); + if(item->buf != NULL) { + DRM_DEBUG("buf index : %d\n", item->buf->idx); } else { - queue = drm_alloc(sizeof(*queue), DRM_MEM_QUEUES); - if(!queue) { - up(&dev->struct_sem); - printk("out of memory\n"); - return -ENOMEM; - } - ++dev->queue_count; - dev->queuelist = drm_alloc(sizeof(*dev->queuelist), - DRM_MEM_QUEUES); - if(!dev->queuelist) { - up(&dev->struct_sem); - drm_free(queue, sizeof(*queue), DRM_MEM_QUEUES); - printk("out of memory\n"); - return -ENOMEM; - } + DRM_DEBUG("Freelist head\n"); } - - memset(queue, 0, sizeof(*queue)); - atomic_set(&queue->use_count, 1); - atomic_set(&queue->finalization, 0); - atomic_set(&queue->block_count, 0); - atomic_set(&queue->block_read, 0); - atomic_set(&queue->block_write, 0); - atomic_set(&queue->total_queued, 0); - atomic_set(&queue->total_flushed, 0); - atomic_set(&queue->total_locks, 0); - - init_waitqueue_head(&queue->write_queue); - init_waitqueue_head(&queue->read_queue); - init_waitqueue_head(&queue->flush_queue); - - queue->flags = 0; - - drm_waitlist_create(&queue->waitlist, dev->dma->buf_count); - - dev->queue_slots = 1; - dev->queuelist[DRM_KERNEL_CONTEXT] = queue; - dev->queue_count--; - - up(&dev->struct_sem); - printk("%d (new)\n", dev->queue_count - 1); - return DRM_KERNEL_CONTEXT; + DRM_DEBUG("item->age : %x\n", item->age); + DRM_DEBUG("item->next : %p\n", item->next); + DRM_DEBUG("item->prev : %p\n", item->prev); } -static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) { - drm_mga_private_t *dev_priv; - drm_map_t *prim_map = NULL; - drm_map_t *sarea_map = NULL; - int temp; - - - dev_priv = drm_alloc(sizeof(drm_mga_private_t), DRM_MEM_DRIVER); - if(dev_priv == NULL) return -ENOMEM; - dev->dev_private = (void *) dev_priv; - - printk("dev_private\n"); - - memset(dev_priv, 0, sizeof(drm_mga_private_t)); - atomic_set(&dev_priv->pending_bufs, 0); - - if((init->reserved_map_idx >= dev->map_count) || - (init->buffer_map_idx >= dev->map_count)) { - mga_dma_cleanup(dev); - printk("reserved_map or buffer_map are invalid\n"); - return -EINVAL; - } +static int mga_freelist_init(drm_device_t *dev) +{ + drm_device_dma_t *dma = dev->dma; + drm_buf_t *buf; + drm_mga_buf_priv_t *buf_priv; + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_freelist_t *item; + int i; + + dev_priv->head = drm_alloc(sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER); + if(dev_priv->head == NULL) return -ENOMEM; + memset(dev_priv->head, 0, sizeof(drm_mga_freelist_t)); + dev_priv->head->age = MGA_BUF_USED; - if(mga_alloc_kernel_queue(dev) != DRM_KERNEL_CONTEXT) { - mga_dma_cleanup(dev); - DRM_ERROR("Kernel context queue not present\n"); + for (i = 0; i < dma->buf_count; i++) { + buf = dma->buflist[ i ]; + buf_priv = buf->dev_private; + item = drm_alloc(sizeof(drm_mga_freelist_t), + DRM_MEM_DRIVER); + if(item == NULL) return -ENOMEM; + memset(item, 0, sizeof(drm_mga_freelist_t)); + item->age = MGA_BUF_FREE; + item->prev = dev_priv->head; + item->next = dev_priv->head->next; + if(dev_priv->head->next != NULL) + dev_priv->head->next->prev = item; + if(item->next == NULL) dev_priv->tail = item; + item->buf = buf; + buf_priv->my_freelist = item; + buf_priv->discard = 0; + dev_priv->head->next = item; } - - dev_priv->reserved_map_idx = init->reserved_map_idx; - dev_priv->buffer_map_idx = init->buffer_map_idx; - sarea_map = dev->maplist[0]; - dev_priv->sarea_priv = (drm_mga_sarea_t *) - ((u8 *)sarea_map->handle + - init->sarea_priv_offset); - printk("sarea_priv\n"); - - /* Scale primary size to the next page */ - dev_priv->primary_size = ((init->primary_size + PAGE_SIZE - 1) / - PAGE_SIZE) * PAGE_SIZE; - dev_priv->warp_ucode_size = init->warp_ucode_size; - dev_priv->chipset = init->chipset; - dev_priv->fbOffset = init->fbOffset; - dev_priv->backOffset = init->backOffset; - dev_priv->depthOffset = init->depthOffset; - dev_priv->textureOffset = init->textureOffset; - dev_priv->textureSize = init->textureSize; - dev_priv->cpp = init->cpp; - dev_priv->sgram = init->sgram; - dev_priv->stride = init->stride; - - dev_priv->frontOrg = init->frontOrg; - dev_priv->backOrg = init->backOrg; - dev_priv->depthOrg = init->depthOrg; - dev_priv->mAccess = init->mAccess; - - printk("memcpy\n"); - memcpy(&dev_priv->WarpIndex, &init->WarpIndex, - sizeof(mgaWarpIndex) * MGA_MAX_WARP_PIPES); - printk("memcpy done\n"); - prim_map = dev->maplist[init->reserved_map_idx]; - dev_priv->prim_phys_head = dev->agp->base + init->reserved_map_agpstart; - temp = init->warp_ucode_size + dev_priv->primary_size; - temp = ((temp + PAGE_SIZE - 1) / - PAGE_SIZE) * PAGE_SIZE; - printk("temp : %x\n", temp); - printk("dev->agp->base: %lx\n", dev->agp->base); - printk("init->reserved_map_agpstart: %x\n", init->reserved_map_agpstart); - - - dev_priv->ioremap = drm_ioremap(dev->agp->base + init->reserved_map_agpstart, - temp); - if(dev_priv->ioremap == NULL) { - printk("Ioremap failed\n"); - mga_dma_cleanup(dev); - return -ENOMEM; + item = dev_priv->head; + while(item) { + mga_freelist_debug(item); + item = item->next; } - - - - dev_priv->prim_head = (u32 *)dev_priv->ioremap; - printk("dev_priv->prim_head : %p\n", dev_priv->prim_head); - dev_priv->current_dma_ptr = dev_priv->prim_head; - dev_priv->prim_num_dwords = 0; - dev_priv->prim_max_dwords = dev_priv->primary_size / 4; + DRM_DEBUG("Head\n"); + mga_freelist_debug(dev_priv->head); + DRM_DEBUG("Tail\n"); + mga_freelist_debug(dev_priv->tail); - printk("dma initialization\n"); - - /* Private is now filled in, initialize the hardware */ - { - PRIMLOCALS; - PRIMRESET( dev_priv ); - PRIMGETPTR( dev_priv ); - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DWGSYNC, 0); - PRIMOUTREG(MGAREG_SOFTRAP, 0); - PRIMADVANCE( dev_priv ); + return 0; +} - /* Poll for the first buffer to insure that - * the status register will be correct - */ - printk("phys_head : %lx\n", phys_head); +static void mga_freelist_cleanup(drm_device_t *dev) +{ + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_freelist_t *item; + drm_mga_freelist_t *prev; + + item = dev_priv->head; + while(item) { + prev = item; + item = item->next; + drm_free(prev, sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER); + } - MGA_WRITE(MGAREG_DWGSYNC, MGA_SYNC_TAG); + dev_priv->head = dev_priv->tail = NULL; +} - while(MGA_READ(MGAREG_DWGSYNC) != MGA_SYNC_TAG) { - int i; - for(i = 0 ; i < 4096; i++) mga_delay(); +/* Frees dispatch lock */ +static inline void mga_dma_quiescent(drm_device_t *dev) +{ + drm_device_dma_t *dma = dev->dma; + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + __volatile__ unsigned int *status = + (__volatile__ unsigned int *)dev_priv->status_page; + unsigned long end; + int i; + + end = jiffies + (HZ*3); + while(1) { + if(!test_and_set_bit(0, &dev_priv->dispatch_lock)) { + break; } - - MGA_WRITE(MGAREG_PRIMADDRESS, phys_head | TT_GENERAL); - - MGA_WRITE(MGAREG_PRIMEND, ((phys_head + num_dwords * 4) | - PDEA_pagpxfer_enable)); - - while(MGA_READ(MGAREG_DWGSYNC) == MGA_SYNC_TAG) { - int i; - for(i = 0; i < 4096; i++) mga_delay(); + if((signed)(end - jiffies) <= 0) { + DRM_ERROR("irqs: %d wanted %d\n", + atomic_read(&dev->total_irq), + atomic_read(&dma->total_lost)); + DRM_ERROR("lockup\n"); + goto out_nolock; } - + for (i = 0 ; i < 2000 ; i++) mga_delay(); } - - printk("dma init was successful\n"); - return 0; + end = jiffies + (HZ*3); + DRM_DEBUG("quiescent status : %x\n", MGA_READ(MGAREG_STATUS)); + while((MGA_READ(MGAREG_STATUS) & 0x00030001) != 0x00020000) { + if((signed)(end - jiffies) <= 0) { + DRM_ERROR("irqs: %d wanted %d\n", + atomic_read(&dev->total_irq), + atomic_read(&dma->total_lost)); + DRM_ERROR("lockup\n"); + goto out_status; + } + for (i = 0 ; i < 2000 ; i++) mga_delay(); + } + DRM_DEBUG("status[1] : %x last_sync_tag : %x\n", status[1], + dev_priv->last_sync_tag); + sarea_priv->dirty |= MGA_DMA_FLUSH; + +out_status: + clear_bit(0, &dev_priv->dispatch_lock); +out_nolock: } -int mga_dma_init(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +#define FREELIST_INITIAL (MGA_DMA_BUF_NR * 2) +#define FREELIST_COMPARE(age) ((age >> 2)) + +unsigned int mga_create_sync_tag(drm_device_t *dev) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - drm_mga_init_t init; + drm_mga_private_t *dev_priv = + (drm_mga_private_t *) dev->dev_private; + unsigned int temp; + drm_buf_t *buf; + drm_mga_buf_priv_t *buf_priv; + drm_device_dma_t *dma = dev->dma; + int i; - copy_from_user_ret(&init, (drm_mga_init_t *)arg, sizeof(init), -EFAULT); + dev_priv->sync_tag++; - switch(init.func) { - case MGA_INIT_DMA: - return mga_dma_initialize(dev, &init); - case MGA_CLEANUP_DMA: - return mga_dma_cleanup(dev); + if(dev_priv->sync_tag < FREELIST_INITIAL) { + dev_priv->sync_tag = FREELIST_INITIAL; } + if(dev_priv->sync_tag > 0x3fffffff) { + mga_flush_queue(dev); + mga_dma_quiescent(dev); + + for (i = 0; i < dma->buf_count; i++) { + buf = dma->buflist[ i ]; + buf_priv = buf->dev_private; + buf_priv->my_freelist->age = MGA_BUF_FREE; + } + + dev_priv->sync_tag = FREELIST_INITIAL; + } + temp = dev_priv->sync_tag << 2; - return -EINVAL; -} - -#define MGA_ILOAD_CMD (DC_opcod_iload | DC_atype_rpl | \ - DC_linear_linear | DC_bltmod_bfcol | \ - (0xC << DC_bop_SHIFT) | DC_sgnzero_enable | \ - DC_shftzero_enable | DC_clipdis_enable) + dev_priv->sarea_priv->last_enqueue = temp; -static void __mga_iload_small(drm_device_t *dev, - drm_buf_t *buf, - int use_agp) -{ - drm_mga_private_t *dev_priv = dev->dev_private; - drm_mga_buf_priv_t *buf_priv = buf->dev_private; - drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; - unsigned long address = (unsigned long)buf->bus_address; - int length = buf->used; - int y1 = buf_priv->boxes[0].y1; - int x1 = buf_priv->boxes[0].x1; - int y2 = buf_priv->boxes[0].y2; - int x2 = buf_priv->boxes[0].x2; - int dstorg = buf_priv->ContextState[MGA_CTXREG_DSTORG]; - int maccess = buf_priv->ContextState[MGA_CTXREG_MACCESS]; - PRIMLOCALS; - - PRIMRESET(dev_priv); - PRIMGETPTR(dev_priv); - - PRIMOUTREG(MGAREG_DSTORG, dstorg | use_agp); - PRIMOUTREG(MGAREG_MACCESS, maccess); - PRIMOUTREG(MGAREG_PITCH, (1 << 15)); - PRIMOUTREG(MGAREG_YDST, y1 * (x2 - x1)); - PRIMOUTREG(MGAREG_LEN, 1); - PRIMOUTREG(MGAREG_FXBNDRY, ((x2 - x1) * (y2 - y1) - 1) << 16); - PRIMOUTREG(MGAREG_AR0, (x2 - x1) * (y2 - y1) - 1); - PRIMOUTREG(MGAREG_AR3, 0); - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DWGCTL+MGAREG_MGA_EXEC, MGA_ILOAD_CMD); - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_SECADDRESS, address | TT_BLIT); - PRIMOUTREG(MGAREG_SECEND, (address + length) | use_agp); - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DWGSYNC, 0); - PRIMOUTREG(MGAREG_SOFTRAP, 0); - PRIMADVANCE(dev_priv); -#if 0 - /* For now we need to set this in the ioctl */ - sarea_priv->dirty |= MGASAREA_NEW_CONTEXT; -#endif - MGA_WRITE(MGAREG_DWGSYNC, MGA_SYNC_TAG); - while(MGA_READ(MGAREG_DWGSYNC) != MGA_SYNC_TAG) ; - - MGA_WRITE(MGAREG_PRIMADDRESS, dev_priv->prim_phys_head | TT_GENERAL); - MGA_WRITE(MGAREG_PRIMEND, (phys_head + num_dwords * 4) | use_agp); + DRM_DEBUG("sync_tag : %x\n", temp); + return temp; } -static void __mga_iload_xy(drm_device_t *dev, - drm_buf_t *buf, - int use_agp) +/* Least recently used : + * These operations are not atomic b/c they are protected by the + * hardware lock */ + +drm_buf_t *mga_freelist_get(drm_device_t *dev) { - drm_mga_private_t *dev_priv = dev->dev_private; - drm_mga_buf_priv_t *buf_priv = buf->dev_private; - drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; - unsigned long address = (unsigned long)buf->bus_address; - int length = buf->used; - int y1 = buf_priv->boxes[0].y1; - int x1 = buf_priv->boxes[0].x1; - int y2 = buf_priv->boxes[0].y2; - int x2 = buf_priv->boxes[0].x2; - int dstorg = buf_priv->ContextState[MGA_CTXREG_DSTORG]; - int maccess = buf_priv->ContextState[MGA_CTXREG_MACCESS]; - int pitch = buf_priv->ServerState[MGA_2DREG_PITCH]; - int width, height; - int texperdword = 0; - PRIMLOCALS; - - width = (x2 - x1); - height = (y2 - y1); - switch((maccess & 0x00000003)) { - case 0: - texperdword = 4; - break; - case 1: - texperdword = 2; - break; - case 2: - texperdword = 1; - break; - default: - DRM_ERROR("Invalid maccess value passed to __mga_iload_xy\n"); - return; - } - - x2 = x1 + width; - x2 = (x2 + (texperdword - 1)) & ~(texperdword - 1); - x1 = (x1 + (texperdword - 1)) & ~(texperdword - 1); - width = x2 - x1; - - PRIMRESET(dev_priv); - PRIMGETPTR(dev_priv); - PRIMOUTREG(MGAREG_DSTORG, dstorg | use_agp); - PRIMOUTREG(MGAREG_MACCESS, maccess); - PRIMOUTREG(MGAREG_PITCH, pitch); - PRIMOUTREG(MGAREG_YDSTLEN, (y1 << 16) | height); - - PRIMOUTREG(MGAREG_FXBNDRY, ((x1+width-1) << 16) | x1); - PRIMOUTREG(MGAREG_AR0, width * height - 1); - PRIMOUTREG(MGAREG_AR3, 0 ); - PRIMOUTREG(MGAREG_DWGCTL+MGAREG_MGA_EXEC, MGA_ILOAD_CMD); - - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_SECADDRESS, address | TT_BLIT); - PRIMOUTREG(MGAREG_SECEND, (address + length) | use_agp); - - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DWGSYNC, 0); - PRIMOUTREG(MGAREG_SOFTRAP, 0); - PRIMADVANCE(dev_priv); -#if 0 - /* For now we need to set this in the ioctl */ - sarea_priv->dirty |= MGASAREA_NEW_CONTEXT; -#endif - MGA_WRITE(MGAREG_DWGSYNC, MGA_SYNC_TAG); - while(MGA_READ(MGAREG_DWGSYNC) != MGA_SYNC_TAG) ; - - MGA_WRITE(MGAREG_PRIMADDRESS, dev_priv->prim_phys_head | TT_GENERAL); - MGA_WRITE(MGAREG_PRIMEND, (phys_head + num_dwords * 4) | use_agp); + drm_mga_private_t *dev_priv = + (drm_mga_private_t *) dev->dev_private; + __volatile__ unsigned int *status = + (__volatile__ unsigned int *)dev_priv->status_page; + drm_mga_freelist_t *prev; + drm_mga_freelist_t *next; + + if((dev_priv->tail->age >> 2) <= FREELIST_COMPARE(status[1])) { + prev = dev_priv->tail->prev; + next = dev_priv->tail; + prev->next = NULL; + next->prev = next->next = NULL; + dev_priv->tail = prev; + next->age = MGA_BUF_USED; + return next->buf; + } + + return NULL; } -static void mga_dma_dispatch_iload(drm_device_t *dev, drm_buf_t *buf) +int mga_freelist_put(drm_device_t *dev, drm_buf_t *buf) { + drm_mga_private_t *dev_priv = + (drm_mga_private_t *) dev->dev_private; drm_mga_buf_priv_t *buf_priv = buf->dev_private; - - int use_agp = PDEA_pagpxfer_enable; - int x1 = buf_priv->boxes[0].x1; - int x2 = buf_priv->boxes[0].x2; - - if((x2 - x1) < 32) { - printk("using iload small\n"); - __mga_iload_small(dev, buf, use_agp); + drm_mga_freelist_t *prev; + drm_mga_freelist_t *head; + drm_mga_freelist_t *next; + + if(buf_priv->my_freelist->age == MGA_BUF_USED) { + /* Discarded buffer, put it on the tail */ + next = buf_priv->my_freelist; + next->age = MGA_BUF_FREE; + prev = dev_priv->tail; + prev->next = next; + next->prev = prev; + next->next = NULL; + dev_priv->tail = next; + DRM_DEBUG("Discarded\n"); } else { - printk("using iload xy\n"); - __mga_iload_xy(dev, buf, use_agp); - } + /* Normally aged buffer, put it on the head + 1, + * as the real head is a sentinal element + */ + next = buf_priv->my_freelist; + head = dev_priv->head; + prev = head->next; + head->next = next; + prev->prev = next; + next->prev = head; + next->next = prev; + } + + return 0; } -static void mga_dma_dispatch_vertex(drm_device_t *dev, drm_buf_t *buf) +static void mga_print_all_primary(drm_device_t *dev) { - drm_mga_private_t *dev_priv = dev->dev_private; - drm_mga_buf_priv_t *buf_priv = buf->dev_private; - unsigned long address = (unsigned long)buf->bus_address; - int length = buf->used; - int use_agp = PDEA_pagpxfer_enable; - int i, count; - PRIMLOCALS; - - PRIMRESET(dev_priv); - - count = buf_priv->nbox; - if (count == 0) - count = 1; - - mgaEmitState( dev_priv, buf_priv ); - - for (i = 0 ; i < count ; i++) { - if (i < buf_priv->nbox) - mgaEmitClipRect( dev_priv, &buf_priv->boxes[i] ); - - PRIMGETPTR(dev_priv); - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_SECADDRESS, address | TT_VERTEX); - PRIMOUTREG( MGAREG_SECEND, (address + length) | use_agp); - - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_DWGSYNC, 0); - PRIMOUTREG( MGAREG_SOFTRAP, 0); - PRIMADVANCE(dev_priv); + drm_mga_private_t *dev_priv = dev->dev_private; + drm_mga_prim_buf_t *prim; + int i; + + DRM_DEBUG("Full list of primarys\n"); + for(i = 0; i < MGA_NUM_PRIM_BUFS; i++) { + prim = dev_priv->prim_bufs[i]; + DRM_DEBUG("index : %d num_dwords : %d " + "max_dwords : %d phy_head : %x\n", + prim->idx, prim->num_dwords, + prim->max_dwords, prim->phys_head); + DRM_DEBUG("sec_used : %d swap_pending : %x " + "in_use : %x force_fire : %d\n", + prim->sec_used, prim->swap_pending, + prim->in_use, atomic_read(&prim->force_fire)); + DRM_DEBUG("needs_overflow : %d\n", + atomic_read(&prim->needs_overflow)); } - - PRIMGETPTR( dev_priv ); - - MGA_WRITE(MGAREG_DWGSYNC, MGA_SYNC_TAG); - while(MGA_READ(MGAREG_DWGSYNC) != MGA_SYNC_TAG) ; - - MGA_WRITE(MGAREG_PRIMADDRESS, dev_priv->prim_phys_head | TT_GENERAL); - MGA_WRITE(MGAREG_PRIMEND, (phys_head + num_dwords * 4) | use_agp); + + DRM_DEBUG("current_idx : %d, next_idx : %d, last_idx : %d\n", + dev_priv->next_prim->idx, dev_priv->last_prim->idx, + dev_priv->current_prim->idx); } - -/* Used internally for the small buffers generated from client state - * information. - */ -static void mga_dma_dispatch_general(drm_device_t *dev, drm_buf_t *buf) +static int mga_init_primary_bufs(drm_device_t *dev, drm_mga_init_t *init) { drm_mga_private_t *dev_priv = dev->dev_private; - unsigned long address = (unsigned long)buf->bus_address; - int length = buf->used; - int use_agp = PDEA_pagpxfer_enable; - PRIMLOCALS; - - PRIMRESET(dev_priv); - PRIMGETPTR(dev_priv); - - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_SECADDRESS, address | TT_GENERAL); - PRIMOUTREG( MGAREG_SECEND, (address + length) | use_agp); - - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_DWGSYNC, 0); - PRIMOUTREG( MGAREG_SOFTRAP, 0); - PRIMADVANCE(dev_priv); - - MGA_WRITE(MGAREG_DWGSYNC, MGA_SYNC_TAG); - while(MGA_READ(MGAREG_DWGSYNC) != MGA_SYNC_TAG) ; - - MGA_WRITE(MGAREG_PRIMADDRESS, dev_priv->prim_phys_head | TT_GENERAL); - MGA_WRITE(MGAREG_PRIMEND, (phys_head + num_dwords * 4) | use_agp); -} + drm_mga_prim_buf_t *prim_buffer; + int i, temp, size_of_buf; + int offset = init->reserved_map_agpstart; -/* Frees dispatch lock */ -static inline void mga_dma_quiescent(drm_device_t *dev) -{ - drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; - - while(1) { - atomic_inc(&dev_priv->dispatch_lock); - if(atomic_read(&dev_priv->dispatch_lock) == 1) { - break; - } else { - atomic_dec(&dev_priv->dispatch_lock); - } - } - while((MGA_READ(MGAREG_STATUS) & 0x00020001) != 0x00020000) ; -#if 0 - MGA_WRITE(MGAREG_DWGSYNC, MGA_SYNC_TAG); -#endif - while(MGA_READ(MGAREG_DWGSYNC) == MGA_SYNC_TAG) ; - MGA_WRITE(MGAREG_DWGSYNC, MGA_SYNC_TAG); - while(MGA_READ(MGAREG_DWGSYNC) != MGA_SYNC_TAG) ; - atomic_dec(&dev_priv->dispatch_lock); + DRM_DEBUG("mga_init_primary_bufs\n"); + dev_priv->primary_size = ((init->primary_size + PAGE_SIZE - 1) / + PAGE_SIZE) * PAGE_SIZE; + DRM_DEBUG("primary_size\n"); + size_of_buf = dev_priv->primary_size / MGA_NUM_PRIM_BUFS; + dev_priv->warp_ucode_size = init->warp_ucode_size; + dev_priv->prim_bufs = drm_alloc(sizeof(drm_mga_prim_buf_t *) * + (MGA_NUM_PRIM_BUFS + 1), + DRM_MEM_DRIVER); + if(dev_priv->prim_bufs == NULL) { + DRM_ERROR("Unable to allocate memory for prim_buf\n"); + return -ENOMEM; + } + DRM_DEBUG("memset\n"); + memset(dev_priv->prim_bufs, + 0, sizeof(drm_mga_prim_buf_t *) * (MGA_NUM_PRIM_BUFS + 1)); + + temp = init->warp_ucode_size + dev_priv->primary_size; + temp = ((temp + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE; + + DRM_DEBUG("temp : %x\n", temp); + DRM_DEBUG("dev->agp->base: %lx\n", dev->agp->base); + DRM_DEBUG("init->reserved_map_agpstart: %x\n", + init->reserved_map_agpstart); + DRM_DEBUG("ioremap\n"); + dev_priv->ioremap = drm_ioremap(dev->agp->base + offset, + temp); + if(dev_priv->ioremap == NULL) { + DRM_DEBUG("Ioremap failed\n"); + return -ENOMEM; + } + init_waitqueue_head(&dev_priv->wait_queue); + + for(i = 0; i < MGA_NUM_PRIM_BUFS; i++) { + DRM_DEBUG("For loop\n"); + prim_buffer = drm_alloc(sizeof(drm_mga_prim_buf_t), + DRM_MEM_DRIVER); + if(prim_buffer == NULL) return -ENOMEM; + DRM_DEBUG("memset\n"); + memset(prim_buffer, 0, sizeof(drm_mga_prim_buf_t)); + prim_buffer->phys_head = offset + dev->agp->base; + prim_buffer->current_dma_ptr = + prim_buffer->head = + (u32 *) (dev_priv->ioremap + + offset - + init->reserved_map_agpstart); + prim_buffer->num_dwords = 0; + prim_buffer->max_dwords = size_of_buf / sizeof(u32); + prim_buffer->max_dwords -= 5; /* Leave room for the softrap */ + prim_buffer->sec_used = 0; + prim_buffer->idx = i; + offset = offset + size_of_buf; + dev_priv->prim_bufs[i] = prim_buffer; + DRM_DEBUG("Looping\n"); + } + dev_priv->current_prim_idx = 0; + dev_priv->next_prim = + dev_priv->last_prim = + dev_priv->current_prim = + dev_priv->prim_bufs[0]; + set_bit(0, &dev_priv->current_prim->in_use); + DRM_DEBUG("init done\n"); + return 0; } -/* Keeps dispatch lock held */ - -static inline int mga_dma_is_ready(drm_device_t *dev) +void mga_fire_primary(drm_device_t *dev, drm_mga_prim_buf_t *prim) { - drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_private_t *dev_priv = dev->dev_private; + drm_device_dma_t *dma = dev->dma; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + int use_agp = PDEA_pagpxfer_enable; + unsigned long end; + int i; + int next_idx; + PRIMLOCALS; + + DRM_DEBUG("mga_fire_primary\n"); + dev_priv->last_sync_tag = mga_create_sync_tag(dev); + dev_priv->last_prim = prim; - atomic_inc(&dev_priv->dispatch_lock); - if(atomic_read(&dev_priv->dispatch_lock) == 1) { - /* We got the lock */ - return 1; + /* We never check for overflow, b/c there is always room */ + PRIMPTR(prim); + if(num_dwords <= 0) { + DRM_DEBUG("num_dwords == 0 when dispatched\n"); + goto out_prim_wait; + } + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DWGSYNC, dev_priv->last_sync_tag); + PRIMOUTREG( MGAREG_SOFTRAP, 0); + PRIMFINISH(prim); + + end = jiffies + (HZ*3); + if(sarea_priv->dirty & MGA_DMA_FLUSH) { + DRM_DEBUG("Dma top flush\n"); + while((MGA_READ(MGAREG_STATUS) & 0x00030001) != 0x00020000) { + if((signed)(end - jiffies) <= 0) { + DRM_ERROR("irqs: %d wanted %d\n", + atomic_read(&dev->total_irq), + atomic_read(&dma->total_lost)); + DRM_ERROR("lockup in fire primary " + "(Dma Top Flush)\n"); + goto out_prim_wait; + } + + for (i = 0 ; i < 4096 ; i++) mga_delay(); + } + sarea_priv->dirty &= ~(MGA_DMA_FLUSH); } else { - atomic_dec(&dev_priv->dispatch_lock); - return 0; + DRM_DEBUG("Status wait\n"); + while((MGA_READ(MGAREG_STATUS) & 0x00020001) != 0x00020000) { + if((signed)(end - jiffies) <= 0) { + DRM_ERROR("irqs: %d wanted %d\n", + atomic_read(&dev->total_irq), + atomic_read(&dma->total_lost)); + DRM_ERROR("lockup in fire primary " + "(Status Wait)\n"); + goto out_prim_wait; + } + + for (i = 0 ; i < 4096 ; i++) mga_delay(); + } } + + mga_flush_write_combine(); + atomic_inc(&dev_priv->pending_bufs); + atomic_inc(&dma->total_lost); + MGA_WRITE(MGAREG_PRIMADDRESS, phys_head | TT_GENERAL); + MGA_WRITE(MGAREG_PRIMEND, (phys_head + num_dwords * 4) | use_agp); + prim->num_dwords = 0; + + next_idx = prim->idx + 1; + if(next_idx >= MGA_NUM_PRIM_BUFS) + next_idx = 0; + + dev_priv->next_prim = dev_priv->prim_bufs[next_idx]; + return; + + out_prim_wait: + prim->num_dwords = 0; + prim->sec_used = 0; + clear_bit(0, &prim->in_use); + wake_up_interruptible(&dev_priv->wait_queue); + clear_bit(0, &prim->swap_pending); + clear_bit(0, &dev_priv->dispatch_lock); + atomic_dec(&dev_priv->pending_bufs); } -static inline int mga_dma_is_ready_no_hold(drm_device_t *dev) +int mga_advance_primary(drm_device_t *dev) { - drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + DECLARE_WAITQUEUE(entry, current); + drm_mga_private_t *dev_priv = dev->dev_private; + drm_mga_prim_buf_t *prim_buffer; + drm_device_dma_t *dma = dev->dma; + int next_prim_idx; + int ret = 0; - atomic_inc(&dev_priv->dispatch_lock); - if(atomic_read(&dev_priv->dispatch_lock) == 1) { - /* We got the lock, but free it */ - atomic_dec(&dev_priv->dispatch_lock); - return 1; - } else { - atomic_dec(&dev_priv->dispatch_lock); - return 0; + /* This needs to reset the primary buffer if available, + * we should collect stats on how many times it bites + * it's tail */ + + next_prim_idx = dev_priv->current_prim_idx + 1; + if(next_prim_idx >= MGA_NUM_PRIM_BUFS) + next_prim_idx = 0; + prim_buffer = dev_priv->prim_bufs[next_prim_idx]; + atomic_set(&dev_priv->in_wait, 1); + + /* In use is cleared in interrupt handler */ + + if(test_and_set_bit(0, &prim_buffer->in_use)) { + add_wait_queue(&dev_priv->wait_queue, &entry); + for (;;) { + current->state = TASK_INTERRUPTIBLE; + mga_dma_schedule(dev, 0); + if(!test_and_set_bit(0, &prim_buffer->in_use)) break; + atomic_inc(&dev->total_sleeps); + atomic_inc(&dma->total_missed_sched); + mga_print_all_primary(dev); + DRM_DEBUG("Schedule in advance\n"); + /* Three second delay */ + schedule_timeout(HZ*3); + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + } + current->state = TASK_RUNNING; + remove_wait_queue(&dev_priv->wait_queue, &entry); + if(ret) return ret; } + atomic_set(&dev_priv->in_wait, 0); + /* This primary buffer is now free to use */ + prim_buffer->current_dma_ptr = prim_buffer->head; + prim_buffer->num_dwords = 0; + prim_buffer->sec_used = 0; + atomic_set(&prim_buffer->needs_overflow, 0); + dev_priv->current_prim = prim_buffer; + dev_priv->current_prim_idx = next_prim_idx; + DRM_DEBUG("Primarys at advance\n"); + mga_print_all_primary(dev); + return 0; } -static void mga_dma_service(int irq, void *device, struct pt_regs *regs) +/* More dynamic performance decisions */ +static inline int mga_decide_to_fire(drm_device_t *dev) { - drm_device_t *dev = (drm_device_t *)device; - drm_device_dma_t *dma = dev->dma; drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_device_dma_t *dma = dev->dma; + + if(atomic_read(&dev_priv->next_prim->force_fire)) + { + atomic_inc(&dma->total_prio); + return 1; + } - atomic_dec(&dev_priv->dispatch_lock); - atomic_inc(&dev->total_irq); - MGA_WRITE(MGAREG_ICLEAR, 0xfa7); - - /* Free previous buffer */ - if (test_and_set_bit(0, &dev->dma_flag)) { - atomic_inc(&dma->total_missed_free); - return; + if (atomic_read(&dev_priv->in_flush) && dev_priv->next_prim->num_dwords) + { + atomic_inc(&dma->total_prio); + return 1; } - if (dma->this_buffer) { - drm_free_buffer(dev, dma->this_buffer); - dma->this_buffer = NULL; + + if(atomic_read(&dev_priv->pending_bufs) <= MGA_NUM_PRIM_BUFS - 1) { + if(test_bit(0, &dev_priv->next_prim->swap_pending)) { + atomic_inc(&dma->total_dmas); + return 1; + } } - clear_bit(0, &dev->dma_flag); - /* Dispatch new buffer */ - queue_task(&dev->tq, &tq_immediate); - mark_bh(IMMEDIATE_BH); + if(atomic_read(&dev_priv->pending_bufs) <= MGA_NUM_PRIM_BUFS / 2) { + if(dev_priv->next_prim->sec_used >= MGA_DMA_BUF_NR / 8) { + atomic_inc(&dma->total_hit); + return 1; + } + } + if(atomic_read(&dev_priv->pending_bufs) >= MGA_NUM_PRIM_BUFS / 2) { + if(dev_priv->next_prim->sec_used >= MGA_DMA_BUF_NR / 4) { + atomic_inc(&dma->total_missed_free); + return 1; + } + } + + atomic_inc(&dma->total_tried); + return 0; } -/* Only called by mga_dma_schedule. */ -static int mga_do_dma(drm_device_t *dev, int locked) +int mga_dma_schedule(drm_device_t *dev, int locked) { - drm_buf_t *buf; - int retcode = 0; - drm_device_dma_t *dma = dev->dma; drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; - drm_mga_buf_priv_t *buf_priv; + drm_device_dma_t *dma = dev->dma; - printk("mga_do_dma\n"); - if (test_and_set_bit(0, &dev->dma_flag)) { + if (test_and_set_bit(0, &dev->dma_flag)) { atomic_inc(&dma->total_missed_dma); return -EBUSY; } - - if (!dma->next_buffer) { - DRM_ERROR("No next_buffer\n"); - clear_bit(0, &dev->dma_flag); - return -EINVAL; - } - - buf = dma->next_buffer; - - printk("context %d, buffer %d\n", buf->context, buf->idx); - - if (buf->list == DRM_LIST_RECLAIM) { - drm_clear_next_buffer(dev); - drm_free_buffer(dev, buf); - clear_bit(0, &dev->dma_flag); - return -EINVAL; - } + + DRM_DEBUG("mga_dma_schedule\n"); - if (!buf->used) { - DRM_ERROR("0 length buffer\n"); - drm_clear_next_buffer(dev); - drm_free_buffer(dev, buf); - clear_bit(0, &dev->dma_flag); - return 0; - } - - if (mga_dma_is_ready(dev) == 0) { - clear_bit(0, &dev->dma_flag); - return -EBUSY; + if(atomic_read(&dev_priv->in_flush) || + atomic_read(&dev_priv->in_wait)) { + locked = 1; } - /* Always hold the hardware lock while dispatching. - */ - if (!locked && !drm_lock_take(&dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT)) { - atomic_inc(&dma->total_missed_lock); - clear_bit(0, &dev->dma_flag); - atomic_dec(&dev_priv->dispatch_lock); - return -EBUSY; + if (!locked && + !drm_lock_take(&dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT)) { + atomic_inc(&dma->total_missed_lock); + clear_bit(0, &dev->dma_flag); + return -EBUSY; } + DRM_DEBUG("I'm locked\n"); - dma->next_queue = dev->queuelist[DRM_KERNEL_CONTEXT]; - drm_clear_next_buffer(dev); - buf->pending = 1; - buf->waiting = 0; - buf->list = DRM_LIST_PEND; - - buf_priv = buf->dev_private; - - printk("dispatch!\n"); - switch (buf_priv->dma_type) { - case MGA_DMA_GENERAL: - mga_dma_dispatch_general(dev, buf); - break; - case MGA_DMA_VERTEX: - mga_dma_dispatch_vertex(dev, buf); - break; -/* case MGA_DMA_SETUP: */ -/* mga_dma_dispatch_setup(dev, address, length); */ -/* break; */ - case MGA_DMA_ILOAD: - mga_dma_dispatch_iload(dev, buf); - break; - default: - printk("bad buffer type %x in dispatch\n", buf_priv->dma_type); - break; + + if(!test_and_set_bit(0, &dev_priv->dispatch_lock)) { + /* Fire dma buffer */ + if(mga_decide_to_fire(dev)) { + DRM_DEBUG("mga_fire_primary\n"); + DRM_DEBUG("idx :%d\n", dev_priv->next_prim->idx); + atomic_set(&dev_priv->next_prim->force_fire, 0); + if(dev_priv->current_prim == dev_priv->next_prim && + dev_priv->next_prim->num_dwords != 0) { + /* Schedule overflow for a later time */ + atomic_set( + &dev_priv->current_prim->needs_overflow, + 1); + } + mga_fire_primary(dev, dev_priv->next_prim); + } else { + clear_bit(0, &dev_priv->dispatch_lock); + } + } else { + DRM_DEBUG("I can't get the dispatch lock\n"); } - atomic_dec(&dev_priv->pending_bufs); - - drm_free_buffer(dev, dma->this_buffer); - dma->this_buffer = buf; - - atomic_add(buf->used, &dma->total_bytes); - atomic_inc(&dma->total_dmas); - + if (!locked) { if (drm_lock_free(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT)) { @@ -692,90 +646,251 @@ static int mga_do_dma(drm_device_t *dev, int locked) } } - clear_bit(0, &dev->dma_flag); - - if(!atomic_read(&dev_priv->pending_bufs)) { - wake_up_interruptible(&dev->queuelist[DRM_KERNEL_CONTEXT]->flush_queue); - } - -#if 0 - wake_up_interruptible(&dev->lock.lock_queue); -#endif + clear_bit(0, &dev->dma_flag); - /* We hold the dispatch lock until the interrupt handler - * frees it - */ - return retcode; + if(atomic_read(&dev_priv->in_flush) == 1 && + dev_priv->next_prim->num_dwords == 0) { + /* Everything is on the hardware */ + DRM_DEBUG("Primarys at Flush\n"); + mga_print_all_primary(dev); + atomic_set(&dev_priv->in_flush, 0); + wake_up_interruptible(&dev_priv->flush_queue); + } + + return 0; } -static void mga_dma_schedule_timer_wrapper(unsigned long dev) +static void mga_dma_service(int irq, void *device, struct pt_regs *regs) { - mga_dma_schedule((drm_device_t *)dev, 0); + drm_device_t *dev = (drm_device_t *)device; + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_prim_buf_t *last_prim_buffer; + __volatile__ unsigned int *status = + (__volatile__ unsigned int *)dev_priv->status_page; + + atomic_inc(&dev->total_irq); + MGA_WRITE(MGAREG_ICLEAR, 0x00000001); + last_prim_buffer = dev_priv->last_prim; + last_prim_buffer->num_dwords = 0; + last_prim_buffer->sec_used = 0; + clear_bit(0, &last_prim_buffer->in_use); + wake_up_interruptible(&dev_priv->wait_queue); + clear_bit(0, &last_prim_buffer->swap_pending); + clear_bit(0, &dev_priv->dispatch_lock); + atomic_dec(&dev_priv->pending_bufs); + dev_priv->sarea_priv->last_dispatch = status[1]; + queue_task(&dev->tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); } -static void mga_dma_schedule_tq_wrapper(void *dev) +static void mga_dma_task_queue(void *device) { + drm_device_t *dev = (drm_device_t *) device; + mga_dma_schedule(dev, 0); } -int mga_dma_schedule(drm_device_t *dev, int locked) +int mga_dma_cleanup(drm_device_t *dev) { - drm_queue_t *q; - drm_buf_t *buf; - int retcode = 0; - int processed = 0; - int missed; - int expire = 20; - drm_device_dma_t *dma = dev->dma; - - printk("mga_dma_schedule\n"); - - if (test_and_set_bit(0, &dev->interrupt_flag)) { - /* Not reentrant */ - atomic_inc(&dma->total_missed_sched); - return -EBUSY; - } - missed = atomic_read(&dma->total_missed_sched); + if(dev->dev_private) { + drm_mga_private_t *dev_priv = + (drm_mga_private_t *) dev->dev_private; + + if(dev_priv->ioremap) { + int temp = (dev_priv->warp_ucode_size + + dev_priv->primary_size + + PAGE_SIZE - 1) / PAGE_SIZE * PAGE_SIZE; -again: - /* There is only one queue: - */ - if (!dma->next_buffer && DRM_WAITCOUNT(dev, DRM_KERNEL_CONTEXT)) { - q = dev->queuelist[DRM_KERNEL_CONTEXT]; - buf = drm_waitlist_get(&q->waitlist); - dma->next_buffer = buf; - dma->next_queue = q; - if (buf && buf->list == DRM_LIST_RECLAIM) { - drm_clear_next_buffer(dev); - drm_free_buffer(dev, buf); + drm_ioremapfree((void *) dev_priv->ioremap, temp); + } + if(dev_priv->status_page != NULL) { + iounmap(dev_priv->status_page); + } + if(dev_priv->real_status_page != 0UL) { + mga_free_page(dev, dev_priv->real_status_page); + } + if(dev_priv->prim_bufs != NULL) { + int i; + for(i = 0; i < MGA_NUM_PRIM_BUFS; i++) { + if(dev_priv->prim_bufs[i] != NULL) { + drm_free(dev_priv->prim_bufs[i], + sizeof(drm_mga_prim_buf_t), + DRM_MEM_DRIVER); + } + } + drm_free(dev_priv->prim_bufs, sizeof(void *) * + (MGA_NUM_PRIM_BUFS + 1), + DRM_MEM_DRIVER); + } + if(dev_priv->head != NULL) { + mga_freelist_cleanup(dev); } + + + drm_free(dev->dev_private, sizeof(drm_mga_private_t), + DRM_MEM_DRIVER); + dev->dev_private = NULL; } - if (dma->next_buffer) { - if (!(retcode = mga_do_dma(dev, locked))) - ++processed; + return 0; +} + +static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) { + drm_mga_private_t *dev_priv; + drm_map_t *sarea_map = NULL; + int i; + + dev_priv = drm_alloc(sizeof(drm_mga_private_t), DRM_MEM_DRIVER); + if(dev_priv == NULL) return -ENOMEM; + dev->dev_private = (void *) dev_priv; + + DRM_DEBUG("dev_private\n"); + + memset(dev_priv, 0, sizeof(drm_mga_private_t)); + atomic_set(&dev_priv->in_flush, 0); + + if((init->reserved_map_idx >= dev->map_count) || + (init->buffer_map_idx >= dev->map_count)) { + mga_dma_cleanup(dev); + DRM_DEBUG("reserved_map or buffer_map are invalid\n"); + return -EINVAL; } + + dev_priv->reserved_map_idx = init->reserved_map_idx; + dev_priv->buffer_map_idx = init->buffer_map_idx; + sarea_map = dev->maplist[0]; + dev_priv->sarea_priv = (drm_mga_sarea_t *) + ((u8 *)sarea_map->handle + + init->sarea_priv_offset); + DRM_DEBUG("sarea_priv\n"); - /* Try again if we succesfully dispatched a buffer, or if someone - * tried to schedule while we were working. - */ - if (--expire) { - if (missed != atomic_read(&dma->total_missed_sched)) { - atomic_inc(&dma->total_lost); - if (mga_dma_is_ready_no_hold(dev)) - goto again; - } + /* Scale primary size to the next page */ + dev_priv->chipset = init->chipset; + dev_priv->frontOffset = init->frontOffset; + dev_priv->backOffset = init->backOffset; + dev_priv->depthOffset = init->depthOffset; + dev_priv->textureOffset = init->textureOffset; + dev_priv->textureSize = init->textureSize; + dev_priv->cpp = init->cpp; + dev_priv->sgram = init->sgram; + dev_priv->stride = init->stride; - if (processed && mga_dma_is_ready_no_hold(dev)) { - atomic_inc(&dma->total_lost); - processed = 0; - goto again; - } + dev_priv->mAccess = init->mAccess; + init_waitqueue_head(&dev_priv->flush_queue); + dev_priv->WarpPipe = -1; + + DRM_DEBUG("chipset: %d ucode_size: %d backOffset: %x depthOffset: %x\n", + dev_priv->chipset, dev_priv->warp_ucode_size, + dev_priv->backOffset, dev_priv->depthOffset); + DRM_DEBUG("cpp: %d sgram: %d stride: %d maccess: %x\n", + dev_priv->cpp, dev_priv->sgram, dev_priv->stride, + dev_priv->mAccess); + + memcpy(&dev_priv->WarpIndex, &init->WarpIndex, + sizeof(drm_mga_warp_index_t) * MGA_MAX_WARP_PIPES); + + for (i = 0 ; i < MGA_MAX_WARP_PIPES ; i++) + DRM_DEBUG("warp pipe %d: installed: %d phys: %lx size: %x\n", + i, + dev_priv->WarpIndex[i].installed, + dev_priv->WarpIndex[i].phys_addr, + dev_priv->WarpIndex[i].size); + + DRM_DEBUG("Doing init prim buffers\n"); + if(mga_init_primary_bufs(dev, init) != 0) { + DRM_ERROR("Can not initialize primary buffers\n"); + mga_dma_cleanup(dev); + return -ENOMEM; } - - clear_bit(0, &dev->interrupt_flag); - - return retcode; + DRM_DEBUG("Done with init prim buffers\n"); + dev_priv->real_status_page = mga_alloc_page(dev); + if(dev_priv->real_status_page == 0UL) { + mga_dma_cleanup(dev); + DRM_ERROR("Can not allocate status page\n"); + return -ENOMEM; + } + DRM_DEBUG("Status page at %lx\n", dev_priv->real_status_page); + + dev_priv->status_page = + ioremap_nocache(virt_to_bus((void *)dev_priv->real_status_page), + PAGE_SIZE); + + if(dev_priv->status_page == NULL) { + mga_dma_cleanup(dev); + DRM_ERROR("Can not remap status page\n"); + return -ENOMEM; + } + + DRM_DEBUG("Status page remapped to %p\n", dev_priv->status_page); + /* Write status page when secend or softrap occurs */ + MGA_WRITE(MGAREG_PRIMPTR, + virt_to_bus((void *)dev_priv->real_status_page) | 0x00000003); + + dev_priv->device = pci_find_device(0x102b, 0x0525, NULL); + if(dev_priv->device == NULL) { + DRM_ERROR("Could not find pci device for card\n"); + mga_dma_cleanup(dev); + return -EINVAL; + } + + DRM_DEBUG("dma initialization\n"); + + /* Private is now filled in, initialize the hardware */ + { + __volatile__ unsigned int *status = + (unsigned int *)dev_priv->status_page; + PRIMLOCALS; + PRIMGETPTR( dev_priv ); + + dev_priv->last_sync_tag = mga_create_sync_tag(dev); + + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DWGSYNC, dev_priv->last_sync_tag); + PRIMOUTREG(MGAREG_SOFTRAP, 0); + /* Poll for the first buffer to insure that + * the status register will be correct + */ + DRM_DEBUG("phys_head : %lx\n", (unsigned long)phys_head); + status[1] = 0; + + mga_flush_write_combine(); + MGA_WRITE(MGAREG_PRIMADDRESS, phys_head | TT_GENERAL); + + MGA_WRITE(MGAREG_PRIMEND, ((phys_head + num_dwords * 4) | + PDEA_pagpxfer_enable)); + + while(MGA_READ(MGAREG_DWGSYNC) != dev_priv->last_sync_tag) ; + DRM_DEBUG("status[0] after initialization : %x\n", status[0]); + DRM_DEBUG("status[1] after initialization : %x\n", status[1]); + } + + if(mga_freelist_init(dev) != 0) { + DRM_ERROR("Could not initialize freelist\n"); + mga_dma_cleanup(dev); + return -ENOMEM; + } + DRM_DEBUG("dma init was successful\n"); + return 0; +} + +int mga_dma_init(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_mga_init_t init; + + copy_from_user_ret(&init, (drm_mga_init_t *)arg, sizeof(init), -EFAULT); + + switch(init.func) { + case MGA_INIT_DMA: + return mga_dma_initialize(dev, &init); + case MGA_CLEANUP_DMA: + return mga_dma_cleanup(dev); + } + + return -EINVAL; } int mga_irq_install(drm_device_t *dev, int irq) @@ -792,7 +907,7 @@ int mga_irq_install(drm_device_t *dev, int irq) dev->irq = irq; up(&dev->struct_sem); - printk("install irq handler %d\n", irq); + DRM_DEBUG("install irq handler %d\n", irq); dev->context_flag = 0; dev->interrupt_flag = 0; @@ -802,13 +917,11 @@ int mga_irq_install(drm_device_t *dev, int irq) dev->dma->this_buffer = NULL; dev->tq.next = NULL; dev->tq.sync = 0; - dev->tq.routine = mga_dma_schedule_tq_wrapper; + dev->tq.routine = mga_dma_task_queue; dev->tq.data = dev; /* Before installing handler */ - MGA_WRITE(MGAREG_ICLEAR, 0xfa7); MGA_WRITE(MGAREG_IEN, 0); - /* Install handler */ if ((retcode = request_irq(dev->irq, mga_dma_service, @@ -820,11 +933,9 @@ int mga_irq_install(drm_device_t *dev, int irq) up(&dev->struct_sem); return retcode; } - /* After installing handler */ - MGA_WRITE(MGAREG_ICLEAR, 0xfa7); + MGA_WRITE(MGAREG_ICLEAR, 0x00000001); MGA_WRITE(MGAREG_IEN, 0x00000001); - return 0; } @@ -838,19 +949,13 @@ int mga_irq_uninstall(drm_device_t *dev) up(&dev->struct_sem); if (!irq) return -EINVAL; - - printk("remove irq handler %d\n", irq); - - MGA_WRITE(MGAREG_ICLEAR, 0xfa7); + DRM_DEBUG("remove irq handler %d\n", irq); + MGA_WRITE(MGAREG_ICLEAR, 0x00000001); MGA_WRITE(MGAREG_IEN, 0); - MGA_WRITE(MGAREG_ICLEAR, 0xfa7); - free_irq(irq, dev); - return 0; } - int mga_control(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -870,36 +975,64 @@ int mga_control(struct inode *inode, struct file *filp, unsigned int cmd, } } -int mga_flush_queue(drm_device_t *dev) +static int mga_flush_queue(drm_device_t *dev) { DECLARE_WAITQUEUE(entry, current); - drm_queue_t *q = dev->queuelist[DRM_KERNEL_CONTEXT]; - drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; int ret = 0; - - printk("mga_flush_queue\n"); - if(atomic_read(&dev_priv->pending_bufs) != 0) { - current->state = TASK_INTERRUPTIBLE; - add_wait_queue(&q->flush_queue, &entry); - for (;;) { - if (!atomic_read(&dev_priv->pending_bufs)) break; - printk("Calling schedule from flush_queue : %d\n", - atomic_read(&dev_priv->pending_bufs)); - mga_dma_schedule(dev, 1); - schedule(); - if (signal_pending(current)) { - ret = -EINTR; /* Can't restart */ - break; - } - } - printk("Exited out of schedule from flush_queue\n"); - current->state = TASK_RUNNING; - remove_wait_queue(&q->flush_queue, &entry); + + if(dev_priv == NULL) { + return 0; } + if(dev_priv->next_prim->num_dwords != 0) { + atomic_set(&dev_priv->in_flush, 1); + current->state = TASK_INTERRUPTIBLE; + add_wait_queue(&dev_priv->flush_queue, &entry); + for (;;) { + mga_dma_schedule(dev, 0); + if (atomic_read(&dev_priv->in_flush) == 0) + break; + atomic_inc(&dev->total_sleeps); + DRM_DEBUG("Schedule in flush_queue\n"); + schedule_timeout(HZ*3); + if (signal_pending(current)) { + ret = -EINTR; /* Can't restart */ + break; + } + } + current->state = TASK_RUNNING; + remove_wait_queue(&dev_priv->flush_queue, &entry); + } + atomic_set(&dev_priv->in_flush, 0); return ret; } +/* Must be called with the lock held */ +void mga_reclaim_buffers(drm_device_t *dev, pid_t pid) +{ + drm_device_dma_t *dma = dev->dma; + int i; + + if (!dma) return; + if(dev->dev_private == NULL) return; + + mga_flush_queue(dev); + + for (i = 0; i < dma->buf_count; i++) { + drm_buf_t *buf = dma->buflist[ i ]; + drm_mga_buf_priv_t *buf_priv = buf->dev_private; + + if (buf->pid == pid) { + if(buf_priv == NULL) return; + /* Only buffers that need to get reclaimed ever + * get set to free */ + if(buf_priv->my_freelist->age == MGA_BUF_USED) + buf_priv->my_freelist->age = MGA_BUF_FREE; + } + } +} + int mga_lock(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -916,16 +1049,15 @@ int mga_lock(struct inode *inode, struct file *filp, unsigned int cmd, current->pid, lock.context); return -EINVAL; } - - printk("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n", - lock.context, current->pid, dev->lock.hw_lock->lock, - lock.flags); - + + DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n", + lock.context, current->pid, dev->lock.hw_lock->lock, + lock.flags); if (lock.context < 0) { return -EINVAL; } - + /* Only one queue: */ @@ -948,8 +1080,7 @@ int mga_lock(struct inode *inode, struct file *filp, unsigned int cmd, /* Contention */ atomic_inc(&dev->total_sleeps); current->state = TASK_INTERRUPTIBLE; - current->policy |= SCHED_YIELD; - printk("Calling lock schedule\n"); + DRM_DEBUG("Calling lock schedule\n"); schedule(); if (signal_pending(current)) { ret = -ERESTARTSYS; @@ -962,17 +1093,60 @@ int mga_lock(struct inode *inode, struct file *filp, unsigned int cmd, if (!ret) { if (lock.flags & _DRM_LOCK_QUIESCENT) { - printk("_DRM_LOCK_QUIESCENT\n"); - ret = mga_flush_queue(dev); - if(ret != 0) { - drm_lock_free(dev, &dev->lock.hw_lock->lock, - lock.context); - } else { - mga_dma_quiescent(dev); - } + DRM_DEBUG("_DRM_LOCK_QUIESCENT\n"); + mga_flush_queue(dev); + mga_dma_quiescent(dev); } } - printk("%d %s\n", lock.context, ret ? "interrupted" : "has lock"); + + DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock"); return ret; } +int mga_flush_ioctl(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_lock_t lock; + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + __volatile__ unsigned int *status = + (__volatile__ unsigned int *)dev_priv->status_page; + int i; + + copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT); + + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("mga_flush_ioctl called without lock held\n"); + return -EINVAL; + } + + if(lock.flags & _DRM_LOCK_FLUSH || lock.flags & _DRM_LOCK_FLUSH_ALL) { + mga_flush_queue(dev); + + if((MGA_READ(MGAREG_STATUS) & 0x00030001) == 0x00020000 && + status[1] != dev_priv->last_sync_tag) + { + DRM_DEBUG("Reseting hardware status\n"); + MGA_WRITE(MGAREG_DWGSYNC, dev_priv->last_sync_tag); + + while(MGA_READ(MGAREG_DWGSYNC) != + dev_priv->last_sync_tag) + { + for(i = 0; i < 4096; i++) mga_delay(); + } + + status[1] = + sarea_priv->last_dispatch = + dev_priv->last_sync_tag; + } else { + sarea_priv->last_dispatch = status[1]; + } + } + if(lock.flags & _DRM_LOCK_QUIESCENT) { + mga_dma_quiescent(dev); + } + + return 0; +} diff --git a/linux/mga_dma.h b/linux/mga_dma.h deleted file mode 100644 index 7f1c57957..000000000 --- a/linux/mga_dma.h +++ /dev/null @@ -1,112 +0,0 @@ -#ifndef MGA_DMA_H -#define MGA_DMA_H - -#include "mga_drm_public.h" - - -/* Isn't this fun. This has to be fixed asap by emitting primary - * dma commands in the 'do_dma' ioctl. - */ -typedef struct { - int dma_type; - - unsigned int ContextState[MGA_CTX_SETUP_SIZE]; - unsigned int ServerState[MGA_2D_SETUP_SIZE]; - unsigned int TexState[2][MGA_TEX_SETUP_SIZE]; - unsigned int WarpPipe; - unsigned int dirty; - - unsigned int nbox; - xf86drmClipRectRec boxes[MGA_NR_SAREA_CLIPRECTS]; -} drm_mga_buf_priv_t; - - -#define MGA_DMA_GENERAL 0 -#define MGA_DMA_VERTEX 1 -#define MGA_DMA_SETUP 2 -#define MGA_DMA_ILOAD 3 - - -#define DWGREG0 0x1c00 -#define DWGREG0_END 0x1dff -#define DWGREG1 0x2c00 -#define DWGREG1_END 0x2dff - -#define ISREG0(r) (r >= DWGREG0 && r <= DWGREG0_END) -#define ADRINDEX0(r) (u8)((r - DWGREG0) >> 2) -#define ADRINDEX1(r) (u8)(((r - DWGREG1) >> 2) | 0x80) -#define ADRINDEX(r) (ISREG0(r) ? ADRINDEX0(r) : ADRINDEX1(r)) - - -/* Macros for inserting commands into a secondary dma buffer. - */ - -#define DMALOCALS u8 tempIndex[4]; u32 *dma_ptr; \ - int outcount, num_dwords; - -#define DMAGETPTR(buf) do { \ - dma_ptr = (u32 *)((u8 *)buf->address + buf->used); \ - outcount = 0; \ - num_dwords = buf->used / 4; \ -} while(0) - -#define DMAADVANCE(buf) do { \ - buf->used = num_dwords * 4; \ -} while(0) - -#define DMAOUTREG(reg, val) do { \ - tempIndex[outcount]=ADRINDEX(reg); \ - dma_ptr[++outcount] = val; \ - if (outcount == 4) { \ - outcount = 0; \ - dma_ptr[0] = *(u32 *)tempIndex; \ - dma_ptr+=5; \ - num_dwords += 5; \ - } \ -}while (0) - - - -#define VERBO 0 - - -/* Primary buffer versions of above -- pretty similar really. - */ -#define PRIMLOCALS u8 tempIndex[4]; u32 *dma_ptr; u32 phys_head; \ - int outcount, num_dwords - -#define PRIMRESET(dev_priv) do { \ - dev_priv->prim_num_dwords = 0; \ - dev_priv->current_dma_ptr = dev_priv->prim_head; \ -} while (0) - -#define PRIMGETPTR(dev_priv) do { \ - dma_ptr = dev_priv->current_dma_ptr; \ - phys_head = dev_priv->prim_phys_head; \ - num_dwords = dev_priv->prim_num_dwords; \ - outcount = 0; \ -} while (0) - -#define PRIMADVANCE(dev_priv) do { \ - dev_priv->prim_num_dwords = num_dwords; \ - dev_priv->current_dma_ptr = dma_ptr; \ -} while (0) - -#define PRIMOUTREG(reg, val) do { \ - tempIndex[outcount]=ADRINDEX(reg); \ - dma_ptr[1+outcount] = val; \ - if( ++outcount == 4) { \ - outcount = 0; \ - dma_ptr[0] = *(u32 *)tempIndex; \ - dma_ptr+=5; \ - num_dwords += 5; \ - } \ - if (VERBO) \ - printk(KERN_INFO \ - "OUT %x val %x dma_ptr %p nr_dwords %d\n", \ - outcount, ADRINDEX(reg), dma_ptr, \ - num_dwords); \ -}while (0) - - -#endif diff --git a/linux/mga_drm.h b/linux/mga_drm.h new file mode 100644 index 000000000..12a858e7a --- /dev/null +++ b/linux/mga_drm.h @@ -0,0 +1,261 @@ +/* mga_drm.h -- Public header for the Matrox g200/g400 driver -*- linux-c -*- + * Created: Tue Jan 25 01:50:01 1999 by jhartmann@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * 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: Jeff Hartmann + * Keith Whitwell + * + * $XFree86$ + */ + +#ifndef _MGA_DRM_H_ +#define _MGA_DRM_H_ + +/* WARNING: If you change any of these defines, make sure to change the + * defines in the Xserver file (xf86drmMga.h) + */ +#ifndef _MGA_DEFINES_ +#define _MGA_DEFINES_ +#define MGA_F 0x1 /* fog */ +#define MGA_A 0x2 /* alpha */ +#define MGA_S 0x4 /* specular */ +#define MGA_T2 0x8 /* multitexture */ + +#define MGA_WARP_TGZ 0 +#define MGA_WARP_TGZF (MGA_F) +#define MGA_WARP_TGZA (MGA_A) +#define MGA_WARP_TGZAF (MGA_F|MGA_A) +#define MGA_WARP_TGZS (MGA_S) +#define MGA_WARP_TGZSF (MGA_S|MGA_F) +#define MGA_WARP_TGZSA (MGA_S|MGA_A) +#define MGA_WARP_TGZSAF (MGA_S|MGA_F|MGA_A) +#define MGA_WARP_T2GZ (MGA_T2) +#define MGA_WARP_T2GZF (MGA_T2|MGA_F) +#define MGA_WARP_T2GZA (MGA_T2|MGA_A) +#define MGA_WARP_T2GZAF (MGA_T2|MGA_A|MGA_F) +#define MGA_WARP_T2GZS (MGA_T2|MGA_S) +#define MGA_WARP_T2GZSF (MGA_T2|MGA_S|MGA_F) +#define MGA_WARP_T2GZSA (MGA_T2|MGA_S|MGA_A) +#define MGA_WARP_T2GZSAF (MGA_T2|MGA_S|MGA_F|MGA_A) + +#define MGA_MAX_G400_PIPES 16 +#define MGA_MAX_G200_PIPES 8 /* no multitex */ + +#define MGA_MAX_WARP_PIPES MGA_MAX_G400_PIPES + +#define MGA_CARD_TYPE_G200 1 +#define MGA_CARD_TYPE_G400 2 +#define MGA_FRONT 0x1 +#define MGA_BACK 0x2 +#define MGA_DEPTH 0x4 + +/* 3d state excluding texture units: + */ +#define MGA_CTXREG_DSTORG 0 /* validated */ +#define MGA_CTXREG_MACCESS 1 +#define MGA_CTXREG_PLNWT 2 +#define MGA_CTXREG_DWGCTL 3 +#define MGA_CTXREG_ALPHACTRL 4 +#define MGA_CTXREG_FOGCOLOR 5 +#define MGA_CTXREG_WFLAG 6 +#define MGA_CTXREG_TDUAL0 7 +#define MGA_CTXREG_TDUAL1 8 +#define MGA_CTXREG_FCOL 9 +#define MGA_CTX_SETUP_SIZE 10 + +/* 2d state + */ +#define MGA_2DREG_PITCH 0 +#define MGA_2D_SETUP_SIZE 1 + +/* Each texture unit has a state: + */ +#define MGA_TEXREG_CTL 0 +#define MGA_TEXREG_CTL2 1 +#define MGA_TEXREG_FILTER 2 +#define MGA_TEXREG_BORDERCOL 3 +#define MGA_TEXREG_ORG 4 /* validated */ +#define MGA_TEXREG_ORG1 5 +#define MGA_TEXREG_ORG2 6 +#define MGA_TEXREG_ORG3 7 +#define MGA_TEXREG_ORG4 8 +#define MGA_TEXREG_WIDTH 9 +#define MGA_TEXREG_HEIGHT 10 +#define MGA_TEX_SETUP_SIZE 11 + +/* What needs to be changed for the current vertex dma buffer? + */ +#define MGA_UPLOAD_CTX 0x1 +#define MGA_UPLOAD_TEX0 0x2 +#define MGA_UPLOAD_TEX1 0x4 +#define MGA_UPLOAD_PIPE 0x8 +#define MGA_UPLOAD_TEX0IMAGE 0x10 +#define MGA_UPLOAD_TEX1IMAGE 0x20 +#define MGA_UPLOAD_2D 0x40 +#define MGA_WAIT_AGE 0x80 /* handled client-side */ +#define MGA_UPLOAD_CLIPRECTS 0x100 /* handled client-side */ +#define MGA_DMA_FLUSH 0x200 /* set when someone gets the lock + quiescent */ + +/* 64 buffers of 16k each, total 1 meg. + */ +#define MGA_DMA_BUF_ORDER 14 +#define MGA_DMA_BUF_SZ (1< - * Keith Whitwell - * - * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/mga_drm_public.h,v 1.1 2000/02/11 17:26:07 dawes Exp $ - */ - -#ifndef _MGA_DRM_PUBLIC_H_ -#define _MGA_DRM_PUBLIC_H_ - -#define MGA_F 0x1 /* fog */ -#define MGA_A 0x2 /* alpha */ -#define MGA_S 0x4 /* specular */ -#define MGA_T2 0x8 /* multitexture */ - -#define MGA_WARP_TGZ 0 -#define MGA_WARP_TGZF (MGA_F) -#define MGA_WARP_TGZA (MGA_A) -#define MGA_WARP_TGZAF (MGA_F|MGA_A) -#define MGA_WARP_TGZS (MGA_S) -#define MGA_WARP_TGZSF (MGA_S|MGA_F) -#define MGA_WARP_TGZSA (MGA_S|MGA_A) -#define MGA_WARP_TGZSAF (MGA_S|MGA_F|MGA_A) -#define MGA_WARP_T2GZ (MGA_T2) -#define MGA_WARP_T2GZF (MGA_T2|MGA_F) -#define MGA_WARP_T2GZA (MGA_T2|MGA_A) -#define MGA_WARP_T2GZAF (MGA_T2|MGA_A|MGA_F) -#define MGA_WARP_T2GZS (MGA_T2|MGA_S) -#define MGA_WARP_T2GZSF (MGA_T2|MGA_S|MGA_F) -#define MGA_WARP_T2GZSA (MGA_T2|MGA_S|MGA_A) -#define MGA_WARP_T2GZSAF (MGA_T2|MGA_S|MGA_F|MGA_A) - - -#define MGA_MAX_G400_PIPES 16 -#define MGA_MAX_G200_PIPES 8 /* no multitex */ - - -#define MGA_MAX_WARP_PIPES MGA_MAX_G400_PIPES - -#define MGA_CARD_TYPE_G200 1 -#define MGA_CARD_TYPE_G400 2 - - -typedef struct _drm_mga_warp_index { - int installed; - unsigned long phys_addr; - int size; -} mgaWarpIndex; - -typedef struct drm_mga_init { - enum { - MGA_INIT_DMA = 0x01, - MGA_CLEANUP_DMA = 0x02 - } func; - int reserved_map_agpstart; - int reserved_map_idx; - int buffer_map_idx; - int sarea_priv_offset; - int primary_size; - int warp_ucode_size; - int fbOffset; - int backOffset; - int depthOffset; - int textureOffset; - int textureSize; - int cpp; - int stride; - int sgram; - int chipset; - mgaWarpIndex WarpIndex[MGA_MAX_WARP_PIPES]; - - /* Redundant? - */ - int frontOrg; - int backOrg; - int depthOrg; - int mAccess; -} drm_mga_init_t; - -typedef struct _xf86drmClipRectRec { - unsigned short x1; - unsigned short y1; - unsigned short x2; - unsigned short y2; -} xf86drmClipRectRec; - -#define MGA_CLEAR_FRONT 0x1 -#define MGA_CLEAR_BACK 0x2 -#define MGA_CLEAR_DEPTH 0x4 - - -/* Each context has a state: - */ -#define MGA_CTXREG_DSTORG 0 /* validated */ -#define MGA_CTXREG_MACCESS 1 -#define MGA_CTXREG_PLNWT 2 -#define MGA_CTXREG_DWGCTL 3 -#define MGA_CTXREG_ALPHACTRL 4 -#define MGA_CTXREG_FOGCOLOR 5 -#define MGA_CTXREG_WFLAG 6 -#define MGA_CTXREG_TDUAL0 7 -#define MGA_CTXREG_TDUAL1 8 -#define MGA_CTX_SETUP_SIZE 9 - -/* 2d state - */ -#define MGA_2DREG_PITCH 0 -#define MGA_2D_SETUP_SIZE 1 - -/* Each texture unit has a state: - */ -#define MGA_TEXREG_CTL 0 -#define MGA_TEXREG_CTL2 1 -#define MGA_TEXREG_FILTER 2 -#define MGA_TEXREG_BORDERCOL 3 -#define MGA_TEXREG_ORG 4 /* validated */ -#define MGA_TEXREG_ORG1 5 -#define MGA_TEXREG_ORG2 6 -#define MGA_TEXREG_ORG3 7 -#define MGA_TEXREG_ORG4 8 -#define MGA_TEXREG_WIDTH 9 -#define MGA_TEXREG_HEIGHT 10 -#define MGA_TEX_SETUP_SIZE 11 - - -/* What needs to be changed for the current vertex dma buffer? - */ -#define MGASAREA_NEW_CONTEXT 0x1 -#define MGASAREA_NEW_TEX0 0x2 -#define MGASAREA_NEW_TEX1 0x4 -#define MGASAREA_NEW_PIPE 0x8 -#define MGASAREA_NEW_2D 0x10 - - -/* Keep this small for testing - */ -#define MGA_NR_SAREA_CLIPRECTS 2 - -/* Upto 128 regions. Minimum region size of 256k. - */ -#define MGA_NR_TEX_REGIONS 128 -#define MGA_MIN_LOG_TEX_GRANULARITY 18 - -typedef struct { - unsigned char next, prev; - unsigned char in_use; - int age; -} mgaTexRegion; - -typedef struct -{ - unsigned int ContextState[MGA_CTX_SETUP_SIZE]; - unsigned int ServerState[MGA_2D_SETUP_SIZE]; - unsigned int TexState[2][MGA_TEX_SETUP_SIZE]; - unsigned int WarpPipe; - unsigned int dirty; - - unsigned int nbox; - xf86drmClipRectRec boxes[MGA_NR_SAREA_CLIPRECTS]; - - /* kernel doesn't touch from here down */ - int ctxOwner; - mgaTexRegion texList[MGA_NR_TEX_REGIONS+1]; - int texAge; -} drm_mga_sarea_t; - - -/* Device specific ioctls: - */ -typedef struct { - int clear_color; - int clear_depth; - int flags; -} drm_mga_clear_t; - - -typedef struct { - int flags; /* not actually used? */ -} drm_mga_swap_t; - -typedef struct { - unsigned int destOrg; - unsigned int mAccess; - unsigned int pitch; - xf86drmClipRectRec texture; - int idx; -} drm_mga_iload_t; - - -#define DRM_IOCTL_MGA_INIT DRM_IOW( 0x40, drm_mga_init_t) -#define DRM_IOCTL_MGA_SWAP DRM_IOW( 0x41, drm_mga_swap_t) -#define DRM_IOCTL_MGA_CLEAR DRM_IOW( 0x42, drm_mga_clear_t) -#define DRM_IOCTL_MGA_ILOAD DRM_IOW( 0x43, drm_mga_iload_t) -#endif diff --git a/linux/mga_drv.c b/linux/mga_drv.c index 8bc25617e..480413549 100644 --- a/linux/mga_drv.c +++ b/linux/mga_drv.c @@ -54,6 +54,7 @@ static struct file_operations mga_fops = { mmap: drm_mmap, read: drm_read, fasync: drm_fasync, + poll: drm_poll, }; static struct miscdevice mga_misc = { @@ -105,9 +106,11 @@ static drm_ioctl_desc_t mga_ioctls[] = { [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = { drm_agp_bind, 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = { drm_agp_unbind, 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_MGA_INIT)] = { mga_dma_init, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_MGA_SWAP)] = { mga_clear_bufs, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_MGA_CLEAR)] = { mga_swap_bufs, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_MGA_ILOAD)] = { mga_iload, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_MGA_SWAP)] = { mga_swap_bufs, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_MGA_CLEAR)] = { mga_clear_bufs, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_MGA_ILOAD)] = { mga_iload, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_MGA_VERTEX)] = { mga_vertex, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_MGA_FLUSH)] = { mga_flush_ioctl, 1, 0 }, }; #define MGA_IOCTL_COUNT DRM_ARRAY_SIZE(mga_ioctls) @@ -380,6 +383,21 @@ int mga_init(void) drm_proc_init(dev); DRM_DEBUG("doing agp init\n"); dev->agp = drm_agp_init(); + if(dev->agp == NULL) { + DRM_DEBUG("The mga drm module requires the agpgart module" + " to function correctly\nPlease load the agpgart" + " module before you load the mga module\n"); + drm_proc_cleanup(); + misc_deregister(&mga_misc); + mga_takedown(dev); + return -ENOMEM; + } +#ifdef CONFIG_MTRR + dev->agp->agp_mtrr = mtrr_add(dev->agp->agp_info.aper_base, + dev->agp->agp_info.aper_size * 1024 * 1024, + MTRR_TYPE_WRCOMB, + 1); +#endif DRM_DEBUG("doing ctxbitmap init\n"); if((retcode = drm_ctxbitmap_init(dev))) { DRM_ERROR("Cannot allocate memory for context bitmap.\n"); @@ -416,6 +434,16 @@ void mga_cleanup(void) } drm_ctxbitmap_cleanup(dev); mga_dma_cleanup(dev); +#ifdef CONFIG_MTRR + if(dev->agp && dev->agp->agp_mtrr) { + int retval; + retval = mtrr_del(dev->agp->agp_mtrr, + dev->agp->agp_info.aper_base, + dev->agp->agp_info.aper_size * 1024*1024); + DRM_DEBUG("mtrr_del = %d\n", retval); + } +#endif + mga_takedown(dev); if (dev->agp) { drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS); diff --git a/linux/mga_drv.h b/linux/mga_drv.h index bc7808b0a..43deb613e 100644 --- a/linux/mga_drv.h +++ b/linux/mga_drv.h @@ -26,12 +26,32 @@ * Authors: Rickard E. (Rik) Faith * Jeff Hartmann * - * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/mga_drv.h,v 1.1 2000/02/11 17:26:08 dawes Exp $ + * $XFree86$ */ #ifndef _MGA_DRV_H_ #define _MGA_DRV_H_ -#include "mga_drm_public.h" + +typedef struct { + unsigned int num_dwords; + unsigned int max_dwords; + u32 *current_dma_ptr; + u32 *head; + u32 phys_head; + int sec_used; + int idx; + int swap_pending; + u32 in_use; + atomic_t force_fire; + atomic_t needs_overflow; +} drm_mga_prim_buf_t; + +typedef struct _drm_mga_freelist { + unsigned int age; + drm_buf_t *buf; + struct _drm_mga_freelist *next; + struct _drm_mga_freelist *prev; +} drm_mga_freelist_t; typedef struct _drm_mga_private { int reserved_map_idx; @@ -40,7 +60,7 @@ typedef struct _drm_mga_private { int primary_size; int warp_ucode_size; int chipset; - int fbOffset; + int frontOffset; int backOffset; int depthOffset; int textureOffset; @@ -49,25 +69,32 @@ typedef struct _drm_mga_private { int stride; int sgram; int use_agp; - mgaWarpIndex WarpIndex[MGA_MAX_G400_PIPES]; + drm_mga_warp_index_t WarpIndex[MGA_MAX_G400_PIPES]; + unsigned int WarpPipe; __volatile__ unsigned long softrap_age; - atomic_t dispatch_lock; + u32 dispatch_lock; + atomic_t in_flush; + atomic_t in_wait; atomic_t pending_bufs; - void *ioremap; - u32 *prim_head; - u32 *current_dma_ptr; - u32 prim_phys_head; - int prim_num_dwords; - int prim_max_dwords; - + unsigned int last_sync_tag; + unsigned int sync_tag; + void *status_page; + unsigned long real_status_page; + u8 *ioremap; + drm_mga_prim_buf_t **prim_bufs; + drm_mga_prim_buf_t *next_prim; + drm_mga_prim_buf_t *last_prim; + drm_mga_prim_buf_t *current_prim; + int current_prim_idx; + struct pci_dev *device; + drm_mga_freelist_t *head; + drm_mga_freelist_t *tail; + wait_queue_head_t flush_queue; /* Processes waiting until flush */ + wait_queue_head_t wait_queue; /* Processes waiting until interrupt */ /* Some validated register values: */ - u32 frontOrg; - u32 backOrg; - u32 depthOrg; u32 mAccess; - } drm_mga_private_t; /* mga_drv.c */ @@ -92,16 +119,18 @@ extern int mga_control(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int mga_lock(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -#if 0 -extern void mga_dma_init(drm_device_t *dev); -extern void mga_dma_cleanup(drm_device_t *dev); -#endif +/* mga_dma_init does init and release */ extern int mga_dma_init(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int mga_dma_cleanup(drm_device_t *dev); +extern int mga_flush_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); -/* mga_dma_init does init and release */ +extern unsigned int mga_create_sync_tag(drm_device_t *dev); +extern drm_buf_t *mga_freelist_get(drm_device_t *dev); +extern int mga_freelist_put(drm_device_t *dev, drm_buf_t *buf); +extern int mga_advance_primary(drm_device_t *dev); /* mga_bufs.c */ @@ -124,6 +153,8 @@ extern int mga_swap_bufs(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int mga_iload(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); +extern int mga_vertex(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); /* mga_context.c */ extern int mga_resctx(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); @@ -144,13 +175,115 @@ extern int mga_context_switch(drm_device_t *dev, int old, int new); extern int mga_context_switch_complete(drm_device_t *dev, int new); +typedef enum { + TT_GENERAL, + TT_BLIT, + TT_VECTOR, + TT_VERTEX +} transferType_t; + +typedef struct { + drm_mga_freelist_t *my_freelist; + int discard; +} drm_mga_buf_priv_t; + +#define DWGREG0 0x1c00 +#define DWGREG0_END 0x1dff +#define DWGREG1 0x2c00 +#define DWGREG1_END 0x2dff + +#define ISREG0(r) (r >= DWGREG0 && r <= DWGREG0_END) +#define ADRINDEX0(r) (u8)((r - DWGREG0) >> 2) +#define ADRINDEX1(r) (u8)(((r - DWGREG1) >> 2) | 0x80) +#define ADRINDEX(r) (ISREG0(r) ? ADRINDEX0(r) : ADRINDEX1(r)) + +#define MGA_VERBOSE 0 +#define MGA_NUM_PRIM_BUFS 8 + +#define PRIMLOCALS u8 tempIndex[4]; u32 *dma_ptr; u32 phys_head; \ + int outcount, num_dwords + +#define PRIM_OVERFLOW(dev, dev_priv, length) do { \ + drm_mga_prim_buf_t *tmp_buf = \ + dev_priv->prim_bufs[dev_priv->current_prim_idx]; \ + if( tmp_buf->max_dwords - tmp_buf->num_dwords < length || \ + tmp_buf->sec_used > MGA_DMA_BUF_NR/2) { \ + atomic_set(&tmp_buf->force_fire, 1); \ + mga_advance_primary(dev); \ + mga_dma_schedule(dev, 1); \ + } else if( atomic_read(&tmp_buf->needs_overflow)) { \ + mga_advance_primary(dev); \ + mga_dma_schedule(dev, 1); \ + } \ +} while(0) + +#define PRIMGETPTR(dev_priv) do { \ + drm_mga_prim_buf_t *tmp_buf = \ + dev_priv->prim_bufs[dev_priv->current_prim_idx]; \ + if(MGA_VERBOSE) \ + DRM_DEBUG("PRIMGETPTR in %s\n", __FUNCTION__); \ + dma_ptr = tmp_buf->current_dma_ptr; \ + num_dwords = tmp_buf->num_dwords; \ + phys_head = tmp_buf->phys_head; \ + outcount = 0; \ +} while(0) + +#define PRIMPTR(prim_buf) do { \ + if(MGA_VERBOSE) \ + DRM_DEBUG("PRIMPTR in %s\n", __FUNCTION__); \ + dma_ptr = prim_buf->current_dma_ptr; \ + num_dwords = prim_buf->num_dwords; \ + phys_head = prim_buf->phys_head; \ + outcount = 0; \ +} while(0) + +#define PRIMFINISH(prim_buf) do { \ + if (MGA_VERBOSE) { \ + DRM_DEBUG( "PRIMFINISH in %s\n", __FUNCTION__); \ + if (outcount & 3) \ + DRM_DEBUG(" --- truncation\n"); \ + } \ + prim_buf->num_dwords = num_dwords; \ + prim_buf->current_dma_ptr = dma_ptr; \ +} while(0) + +#define PRIMADVANCE(dev_priv) do { \ +drm_mga_prim_buf_t *tmp_buf = \ + dev_priv->prim_bufs[dev_priv->current_prim_idx]; \ + if (MGA_VERBOSE) { \ + DRM_DEBUG("PRIMADVANCE in %s\n", __FUNCTION__); \ + if (outcount & 3) \ + DRM_DEBUG(" --- truncation\n"); \ + } \ + tmp_buf->num_dwords = num_dwords; \ + tmp_buf->current_dma_ptr = dma_ptr; \ +} while (0) + +#define PRIMUPDATE(dev_priv) do { \ + drm_mga_prim_buf_t *tmp_buf = \ + dev_priv->prim_bufs[dev_priv->current_prim_idx]; \ + tmp_buf->sec_used++; \ +} while (0) + +#define PRIMOUTREG(reg, val) do { \ + tempIndex[outcount]=ADRINDEX(reg); \ + dma_ptr[1+outcount] = val; \ + if (MGA_VERBOSE) \ + DRM_DEBUG(" PRIMOUT %d: 0x%x -- 0x%x\n", \ + num_dwords + 1 + outcount, ADRINDEX(reg), val); \ + if( ++outcount == 4) { \ + outcount = 0; \ + dma_ptr[0] = *(u32 *)tempIndex; \ + dma_ptr+=5; \ + num_dwords += 5; \ + } \ +}while (0) + +/* A reduced set of the mga registers. + */ #define MGAREG_MGA_EXEC 0x0100 -#define MGAREG_AGP_PLL 0x1e4c #define MGAREG_ALPHACTRL 0x2c7c -#define MGAREG_ALPHASTART 0x2c70 -#define MGAREG_ALPHAXINC 0x2c74 -#define MGAREG_ALPHAYINC 0x2c78 #define MGAREG_AR0 0x1c60 #define MGAREG_AR1 0x1c64 #define MGAREG_AR2 0x1c68 @@ -158,39 +291,16 @@ extern int mga_context_switch_complete(drm_device_t *dev, int new); #define MGAREG_AR4 0x1c70 #define MGAREG_AR5 0x1c74 #define MGAREG_AR6 0x1c78 -#define MGAREG_BCOL 0x1c20 #define MGAREG_CXBNDRY 0x1c80 #define MGAREG_CXLEFT 0x1ca0 #define MGAREG_CXRIGHT 0x1ca4 #define MGAREG_DMAPAD 0x1c54 -#define MGAREG_DR0_Z32LSB 0x2c50 -#define MGAREG_DR0_Z32MSB 0x2c54 -#define MGAREG_DR2_Z32LSB 0x2c60 -#define MGAREG_DR2_Z32MSB 0x2c64 -#define MGAREG_DR3_Z32LSB 0x2c68 -#define MGAREG_DR3_Z32MSB 0x2c6c -#define MGAREG_DR0 0x1cc0 -#define MGAREG_DR2 0x1cc8 -#define MGAREG_DR3 0x1ccc -#define MGAREG_DR4 0x1cd0 -#define MGAREG_DR6 0x1cd8 -#define MGAREG_DR7 0x1cdc -#define MGAREG_DR8 0x1ce0 -#define MGAREG_DR10 0x1ce8 -#define MGAREG_DR11 0x1cec -#define MGAREG_DR12 0x1cf0 -#define MGAREG_DR14 0x1cf8 -#define MGAREG_DR15 0x1cfc #define MGAREG_DSTORG 0x2cb8 -#define MGAREG_DWG_INDIR_WT 0x1e80 #define MGAREG_DWGCTL 0x1c00 #define MGAREG_DWGSYNC 0x2c4c #define MGAREG_FCOL 0x1c24 #define MGAREG_FIFOSTATUS 0x1e10 #define MGAREG_FOGCOL 0x1cf4 -#define MGAREG_FOGSTART 0x1cc4 -#define MGAREG_FOGXINC 0x1cd4 -#define MGAREG_FOGYINC 0x1ce4 #define MGAREG_FXBNDRY 0x1c84 #define MGAREG_FXLEFT 0x1ca8 #define MGAREG_FXRIGHT 0x1cac @@ -198,44 +308,22 @@ extern int mga_context_switch_complete(drm_device_t *dev, int new); #define MGAREG_IEN 0x1e1c #define MGAREG_LEN 0x1c5c #define MGAREG_MACCESS 0x1c04 -#define MGAREG_MCTLWTST 0x1c08 -#define MGAREG_MEMRDBK 0x1e44 -#define MGAREG_OPMODE 0x1e54 -#define MGAREG_PAT0 0x1c10 -#define MGAREG_PAT1 0x1c14 #define MGAREG_PITCH 0x1c8c #define MGAREG_PLNWT 0x1c1c #define MGAREG_PRIMADDRESS 0x1e58 #define MGAREG_PRIMEND 0x1e5c #define MGAREG_PRIMPTR 0x1e50 -#define MGAREG_RST 0x1e40 #define MGAREG_SECADDRESS 0x2c40 #define MGAREG_SECEND 0x2c44 #define MGAREG_SETUPADDRESS 0x2cd0 #define MGAREG_SETUPEND 0x2cd4 -#define MGAREG_SGN 0x1c58 -#define MGAREG_SHIFT 0x1c50 #define MGAREG_SOFTRAP 0x2c48 -#define MGAREG_SPECBSTART 0x2c98 -#define MGAREG_SPECBXINC 0x2c9c -#define MGAREG_SPECBYINC 0x2ca0 -#define MGAREG_SPECGSTART 0x2c8c -#define MGAREG_SPECGXINC 0x2c90 -#define MGAREG_SPECGYINC 0x2c94 -#define MGAREG_SPECRSTART 0x2c80 -#define MGAREG_SPECRXINC 0x2c84 -#define MGAREG_SPECRYINC 0x2c88 -#define MGAREG_SRC0 0x1c30 -#define MGAREG_SRC1 0x1c34 -#define MGAREG_SRC2 0x1c38 -#define MGAREG_SRC3 0x1c3c #define MGAREG_SRCORG 0x2cb4 #define MGAREG_STATUS 0x1e14 #define MGAREG_STENCIL 0x2cc8 #define MGAREG_STENCILCTL 0x2ccc #define MGAREG_TDUALSTAGE0 0x2cf8 #define MGAREG_TDUALSTAGE1 0x2cfc -#define MGAREG_TEST0 0x1e48 #define MGAREG_TEXBORDERCOL 0x2c5c #define MGAREG_TEXCTL 0x2c30 #define MGAREG_TEXCTL2 0x2c3c @@ -249,18 +337,6 @@ extern int mga_context_switch_complete(drm_device_t *dev, int new); #define MGAREG_TEXTRANS 0x2c34 #define MGAREG_TEXTRANSHIGH 0x2c38 #define MGAREG_TEXWIDTH 0x2c28 -#define MGAREG_TMR0 0x2c00 -#define MGAREG_TMR1 0x2c04 -#define MGAREG_TMR2 0x2c08 -#define MGAREG_TMR3 0x2c0c -#define MGAREG_TMR4 0x2c10 -#define MGAREG_TMR5 0x2c14 -#define MGAREG_TMR6 0x2c18 -#define MGAREG_TMR7 0x2c1c -#define MGAREG_TMR8 0x2c20 -#define MGAREG_VBIADDR0 0x3e08 -#define MGAREG_VBIADDR1 0x3e0c -#define MGAREG_VCOUNT 0x1e20 #define MGAREG_WACCEPTSEQ 0x1dd4 #define MGAREG_WCODEADDR 0x1e6c #define MGAREG_WFLAG 0x1dc4 @@ -270,18 +346,8 @@ extern int mga_context_switch_complete(drm_device_t *dev, int new); #define MGAREG_WGETMSB 0x1dc8 #define MGAREG_WIADDR 0x1dc0 #define MGAREG_WIADDR2 0x1dd8 -#define MGAREG_WIADDRNB 0x1e60 -#define MGAREG_WIADDRNB1 0x1e04 -#define MGAREG_WIADDRNB2 0x1e00 -#define MGAREG_WIMEMADDR 0x1e68 -#define MGAREG_WIMEMDATA 0x2000 -#define MGAREG_WIMEMDATA1 0x2100 #define MGAREG_WMISC 0x1e70 -#define MGAREG_WR 0x2d00 #define MGAREG_WVRTXSZ 0x1dcc -#define MGAREG_XDST 0x1cb0 -#define MGAREG_XYEND 0x1c44 -#define MGAREG_XYSTRT 0x1c40 #define MGAREG_YBOT 0x1c9c #define MGAREG_YDST 0x1c90 #define MGAREG_YDSTLEN 0x1c88 @@ -289,4 +355,40 @@ extern int mga_context_switch_complete(drm_device_t *dev, int new); #define MGAREG_YTOP 0x1c98 #define MGAREG_ZORG 0x1c0c +#define DC_atype_rstr 0x10 +#define DC_atype_blk 0x40 +#define PDEA_pagpxfer_enable 0x2 +#define WIA_wmode_suspend 0x0 +#define WIA_wmode_start 0x3 +#define WIA_wagp_agp 0x4 +#define DC_opcod_trap 0x4 +#define DC_arzero_enable 0x1000 +#define DC_sgnzero_enable 0x2000 +#define DC_shftzero_enable 0x4000 +#define DC_bop_SHIFT 16 +#define DC_clipdis_enable 0x80000000 +#define DC_solid_enable 0x800 +#define DC_transc_enable 0x40000000 +#define DC_opcod_bitblt 0x8 +#define DC_atype_rpl 0x0 +#define DC_linear_xy 0x0 +#define DC_solid_disable 0x0 +#define DC_arzero_disable 0x0 +#define DC_bltmod_bfcol 0x4000000 +#define DC_pattern_disable 0x0 +#define DC_transc_disable 0x0 + +#define MGA_CLEAR_CMD (DC_opcod_trap | DC_arzero_enable | \ + DC_sgnzero_enable | DC_shftzero_enable | \ + (0xC << DC_bop_SHIFT) | DC_clipdis_enable | \ + DC_solid_enable | DC_transc_enable) + + +#define MGA_COPY_CMD (DC_opcod_bitblt | DC_atype_rpl | DC_linear_xy | \ + DC_solid_disable | DC_arzero_disable | \ + DC_sgnzero_enable | DC_shftzero_enable | \ + (0xC << DC_bop_SHIFT) | DC_bltmod_bfcol | \ + DC_pattern_disable | DC_transc_disable | \ + DC_clipdis_enable) \ + #endif diff --git a/linux/mga_state.c b/linux/mga_state.c index d09881bad..a70f86d22 100644 --- a/linux/mga_state.c +++ b/linux/mga_state.c @@ -26,189 +26,217 @@ * Authors: Jeff Hartmann * Keith Whitwell * - * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/mga_state.c,v 1.1 2000/02/11 17:26:08 dawes Exp $ + * $XFree86$ * */ #define __NO_VERSION__ #include "drmP.h" #include "mga_drv.h" -#include "mgareg_flags.h" -#include "mga_dma.h" -#include "mga_state.h" #include "drm.h" -void mgaEmitClipRect( drm_mga_private_t *dev_priv, xf86drmClipRectRec *box ) +static void mgaEmitClipRect( drm_mga_private_t *dev_priv, + drm_clip_rect_t *box ) { + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int *regs = sarea_priv->ContextState; PRIMLOCALS; + /* This takes 10 dwords */ PRIMGETPTR( dev_priv ); + + /* Force reset of dwgctl (eliminates clip disable) */ + PRIMOUTREG( MGAREG_DMAPAD, 0 ); + PRIMOUTREG( MGAREG_DWGSYNC, dev_priv->last_sync_tag - 1 ); + PRIMOUTREG( MGAREG_DWGSYNC, dev_priv->last_sync_tag - 1 ); + PRIMOUTREG( MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL] ); - /* The G400 seems to have an issue with the second WARP not - * stalling clipper register writes. This bothers me, but the only - * way I could get it to never clip the last triangle under any - * circumstances is by inserting TWO dwgsync commands. - */ - if (dev_priv->chipset == MGA_CARD_TYPE_G400) { - PRIMOUTREG( MGAREG_DWGSYNC, 0 ); - PRIMOUTREG( MGAREG_DWGSYNC, 0 ); - } - + PRIMOUTREG( MGAREG_DMAPAD, 0 ); PRIMOUTREG( MGAREG_CXBNDRY, ((box->x2)<<16)|(box->x1) ); - PRIMOUTREG( MGAREG_YTOP, box->y1 * dev_priv->stride ); - PRIMOUTREG( MGAREG_YBOT, box->y2 * dev_priv->stride ); + PRIMOUTREG( MGAREG_YTOP, box->y1 * dev_priv->stride/2 ); + PRIMOUTREG( MGAREG_YBOT, box->y2 * dev_priv->stride/2 ); + PRIMADVANCE( dev_priv ); } - -static void mgaEmitContext(drm_mga_private_t *dev_priv, - drm_mga_buf_priv_t *buf_priv) +static void mgaEmitContext(drm_mga_private_t *dev_priv ) { - unsigned int *regs = buf_priv->ContextState; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int *regs = sarea_priv->ContextState; PRIMLOCALS; + /* This takes a max of 15 dwords */ PRIMGETPTR( dev_priv ); + PRIMOUTREG( MGAREG_DSTORG, regs[MGA_CTXREG_DSTORG] ); PRIMOUTREG( MGAREG_MACCESS, regs[MGA_CTXREG_MACCESS] ); PRIMOUTREG( MGAREG_PLNWT, regs[MGA_CTXREG_PLNWT] ); PRIMOUTREG( MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL] ); + PRIMOUTREG( MGAREG_ALPHACTRL, regs[MGA_CTXREG_ALPHACTRL] ); PRIMOUTREG( MGAREG_FOGCOL, regs[MGA_CTXREG_FOGCOLOR] ); PRIMOUTREG( MGAREG_WFLAG, regs[MGA_CTXREG_WFLAG] ); + PRIMOUTREG( MGAREG_ZORG, dev_priv->depthOffset ); /* invarient */ if (dev_priv->chipset == MGA_CARD_TYPE_G400) { PRIMOUTREG( MGAREG_WFLAG1, regs[MGA_CTXREG_WFLAG] ); PRIMOUTREG( MGAREG_TDUALSTAGE0, regs[MGA_CTXREG_TDUAL0] ); PRIMOUTREG( MGAREG_TDUALSTAGE1, regs[MGA_CTXREG_TDUAL1] ); - } + PRIMOUTREG( MGAREG_FCOL, regs[MGA_CTXREG_FCOL] ); + } else { + PRIMOUTREG( MGAREG_FCOL, regs[MGA_CTXREG_FCOL] ); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + } PRIMADVANCE( dev_priv ); } -static void mgaG200EmitTex( drm_mga_private_t *dev_priv, - drm_mga_buf_priv_t *buf_priv ) +static void mgaG200EmitTex( drm_mga_private_t *dev_priv ) { - unsigned int *regs = buf_priv->TexState[0]; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int *regs = sarea_priv->TexState[0]; PRIMLOCALS; PRIMGETPTR( dev_priv ); + + /* This takes 20 dwords */ + PRIMOUTREG(MGAREG_TEXCTL2, regs[MGA_TEXREG_CTL2] ); PRIMOUTREG(MGAREG_TEXCTL, regs[MGA_TEXREG_CTL] ); PRIMOUTREG(MGAREG_TEXFILTER, regs[MGA_TEXREG_FILTER] ); PRIMOUTREG(MGAREG_TEXBORDERCOL, regs[MGA_TEXREG_BORDERCOL] ); + PRIMOUTREG(MGAREG_TEXORG, regs[MGA_TEXREG_ORG] ); PRIMOUTREG(MGAREG_TEXORG1, regs[MGA_TEXREG_ORG1] ); PRIMOUTREG(MGAREG_TEXORG2, regs[MGA_TEXREG_ORG2] ); PRIMOUTREG(MGAREG_TEXORG3, regs[MGA_TEXREG_ORG3] ); + PRIMOUTREG(MGAREG_TEXORG4, regs[MGA_TEXREG_ORG4] ); PRIMOUTREG(MGAREG_TEXWIDTH, regs[MGA_TEXREG_WIDTH] ); - PRIMOUTREG(MGAREG_TEXHEIGHT, regs[MGA_TEXREG_HEIGHT] ); - + PRIMOUTREG(MGAREG_TEXHEIGHT, regs[MGA_TEXREG_HEIGHT] ); PRIMOUTREG(0x2d00 + 24*4, regs[MGA_TEXREG_WIDTH] ); + PRIMOUTREG(0x2d00 + 34*4, regs[MGA_TEXREG_HEIGHT] ); + PRIMOUTREG( MGAREG_TEXTRANS, 0xffff ); + PRIMOUTREG( MGAREG_TEXTRANSHIGH, 0xffff ); + PRIMOUTREG( MGAREG_DMAPAD, 0 ); PRIMADVANCE( dev_priv ); } -static void mgaG400EmitTex0( drm_mga_private_t *dev_priv, - drm_mga_buf_priv_t *buf_priv ) +static void mgaG400EmitTex0( drm_mga_private_t *dev_priv ) { - unsigned int *regs = buf_priv->TexState[0]; - int multitex = buf_priv->WarpPipe & MGA_T2; - + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int *regs = sarea_priv->TexState[0]; + int multitex = sarea_priv->WarpPipe & MGA_T2; PRIMLOCALS; + PRIMGETPTR( dev_priv ); + + /* This takes a max of 30 dwords */ PRIMOUTREG(MGAREG_TEXCTL2, regs[MGA_TEXREG_CTL2] ); PRIMOUTREG(MGAREG_TEXCTL, regs[MGA_TEXREG_CTL] ); PRIMOUTREG(MGAREG_TEXFILTER, regs[MGA_TEXREG_FILTER] ); PRIMOUTREG(MGAREG_TEXBORDERCOL, regs[MGA_TEXREG_BORDERCOL] ); + PRIMOUTREG(MGAREG_TEXORG, regs[MGA_TEXREG_ORG] ); PRIMOUTREG(MGAREG_TEXORG1, regs[MGA_TEXREG_ORG1] ); PRIMOUTREG(MGAREG_TEXORG2, regs[MGA_TEXREG_ORG2] ); PRIMOUTREG(MGAREG_TEXORG3, regs[MGA_TEXREG_ORG3] ); + PRIMOUTREG(MGAREG_TEXORG4, regs[MGA_TEXREG_ORG4] ); PRIMOUTREG(MGAREG_TEXWIDTH, regs[MGA_TEXREG_WIDTH] ); - PRIMOUTREG(MGAREG_TEXHEIGHT, regs[MGA_TEXREG_HEIGHT] ); - + PRIMOUTREG(MGAREG_TEXHEIGHT, regs[MGA_TEXREG_HEIGHT] ); PRIMOUTREG(0x2d00 + 49*4, 0); + PRIMOUTREG(0x2d00 + 57*4, 0); PRIMOUTREG(0x2d00 + 53*4, 0); PRIMOUTREG(0x2d00 + 61*4, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0 ); if (!multitex) { PRIMOUTREG(0x2d00 + 52*4, 0x40 ); PRIMOUTREG(0x2d00 + 60*4, 0x40 ); + PRIMOUTREG( MGAREG_DMAPAD, 0 ); + PRIMOUTREG( MGAREG_DMAPAD, 0 ); } - PRIMOUTREG(0x2d00 + 54*4, regs[MGA_TEXREG_WIDTH] | 0x40 ); - PRIMOUTREG(0x2d00 + 62*4, regs[MGA_TEXREG_HEIGHT] | 0x40 ); + PRIMOUTREG( 0x2d00 + 54*4, regs[MGA_TEXREG_WIDTH] | 0x40 ); + PRIMOUTREG( 0x2d00 + 62*4, regs[MGA_TEXREG_HEIGHT] | 0x40 ); + PRIMOUTREG( MGAREG_TEXTRANS, 0xffff ); + PRIMOUTREG( MGAREG_TEXTRANSHIGH, 0xffff ); PRIMADVANCE( dev_priv ); } #define TMC_map1_enable 0x80000000 - -static void mgaG400EmitTex1( drm_mga_private_t *dev_priv, - drm_mga_buf_priv_t *buf_priv ) +static void mgaG400EmitTex1( drm_mga_private_t *dev_priv ) { - drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned int *regs = sarea_priv->TexState[1]; - PRIMLOCALS; + PRIMGETPTR(dev_priv); + /* This takes 25 dwords */ PRIMOUTREG(MGAREG_TEXCTL2, regs[MGA_TEXREG_CTL2] | TMC_map1_enable); PRIMOUTREG(MGAREG_TEXCTL, regs[MGA_TEXREG_CTL] ); PRIMOUTREG(MGAREG_TEXFILTER, regs[MGA_TEXREG_FILTER] ); PRIMOUTREG(MGAREG_TEXBORDERCOL, regs[MGA_TEXREG_BORDERCOL] ); + PRIMOUTREG(MGAREG_TEXORG, regs[MGA_TEXREG_ORG] ); PRIMOUTREG(MGAREG_TEXORG1, regs[MGA_TEXREG_ORG1] ); PRIMOUTREG(MGAREG_TEXORG2, regs[MGA_TEXREG_ORG2] ); PRIMOUTREG(MGAREG_TEXORG3, regs[MGA_TEXREG_ORG3] ); + PRIMOUTREG(MGAREG_TEXORG4, regs[MGA_TEXREG_ORG4] ); PRIMOUTREG(MGAREG_TEXWIDTH, regs[MGA_TEXREG_WIDTH] ); - PRIMOUTREG(MGAREG_TEXHEIGHT, regs[MGA_TEXREG_HEIGHT] ); - + PRIMOUTREG(MGAREG_TEXHEIGHT, regs[MGA_TEXREG_HEIGHT] ); PRIMOUTREG(0x2d00 + 49*4, 0); + PRIMOUTREG(0x2d00 + 57*4, 0); PRIMOUTREG(0x2d00 + 53*4, 0); PRIMOUTREG(0x2d00 + 61*4, 0); - PRIMOUTREG(0x2d00 + 52*4, regs[MGA_TEXREG_WIDTH] | 0x40 ); - PRIMOUTREG(0x2d00 + 60*4, regs[MGA_TEXREG_HEIGHT] | 0x40 ); + PRIMOUTREG(0x2d00 + 60*4, regs[MGA_TEXREG_HEIGHT] | 0x40 ); + PRIMOUTREG( MGAREG_TEXTRANS, 0xffff ); + PRIMOUTREG( MGAREG_TEXTRANSHIGH, 0xffff ); PRIMOUTREG(MGAREG_TEXCTL2, regs[MGA_TEXREG_CTL2] ); - PRIMADVANCE( dev_priv ); + PRIMADVANCE( dev_priv ); } - -static void mgaG400EmitPipe(drm_mga_private_t *dev_priv, - drm_mga_buf_priv_t *buf_priv) +static void mgaG400EmitPipe(drm_mga_private_t *dev_priv ) { - drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned int pipe = sarea_priv->WarpPipe; float fParam = 12800.0f; PRIMLOCALS; PRIMGETPTR(dev_priv); - PRIMOUTREG(MGAREG_WIADDR2, WIA_wmode_suspend); + + /* This takes 25 dwords */ /* Establish vertex size. */ if (pipe & MGA_T2) { + PRIMOUTREG(MGAREG_WIADDR2, WIA_wmode_suspend); PRIMOUTREG(MGAREG_WVRTXSZ, 0x00001e09); PRIMOUTREG(MGAREG_WACCEPTSEQ, 0x1e000000); + PRIMOUTREG(MGAREG_WFLAG, 0); } else { + PRIMOUTREG(MGAREG_WIADDR2, WIA_wmode_suspend); PRIMOUTREG(MGAREG_WVRTXSZ, 0x00001807); PRIMOUTREG(MGAREG_WACCEPTSEQ, 0x18000000); - } - - PRIMOUTREG(MGAREG_WFLAG, 0); - PRIMOUTREG(MGAREG_WFLAG1, 0); - + PRIMOUTREG(MGAREG_WFLAG, 0); + } + + PRIMOUTREG(MGAREG_WFLAG1, 0); PRIMOUTREG(0x2d00 + 56*4, *((u32 *)(&fParam))); PRIMOUTREG(MGAREG_DMAPAD, 0); PRIMOUTREG(MGAREG_DMAPAD, 0); @@ -227,19 +255,21 @@ static void mgaG400EmitPipe(drm_mga_private_t *dev_priv, PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff); PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff); PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff); - PRIMOUTREG(MGAREG_WIADDR2, (dev_priv->WarpIndex[pipe].phys_addr | - WIA_wmode_start | WIA_wagp_agp)); + PRIMOUTREG(MGAREG_WIADDR2, (__u32)(dev_priv->WarpIndex[pipe].phys_addr | + WIA_wmode_start | WIA_wagp_agp)); PRIMADVANCE(dev_priv); } -static void mgaG200EmitPipe( drm_mga_private_t *dev_priv, - drm_mga_buf_priv_t *buf_priv ) +static void mgaG200EmitPipe( drm_mga_private_t *dev_priv ) { - drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned int pipe = sarea_priv->WarpPipe; PRIMLOCALS; PRIMGETPTR(dev_priv); + + /* This takes 15 dwords */ + PRIMOUTREG(MGAREG_WIADDR, WIA_wmode_suspend); PRIMOUTREG(MGAREG_WVRTXSZ, 7); PRIMOUTREG(MGAREG_WFLAG, 0); @@ -254,109 +284,629 @@ static void mgaG200EmitPipe( drm_mga_private_t *dev_priv, PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff); PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff); PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff); - PRIMOUTREG(MGAREG_WIADDR, (dev_priv->WarpIndex[pipe].phys_addr | - WIA_wmode_start | WIA_wagp_agp)); + PRIMOUTREG(MGAREG_WIADDR, (__u32)(dev_priv->WarpIndex[pipe].phys_addr | + WIA_wmode_start | WIA_wagp_agp)); PRIMADVANCE(dev_priv); } -void mgaEmitState( drm_mga_private_t *dev_priv, drm_mga_buf_priv_t *buf_priv ) +static void mgaEmitState( drm_mga_private_t *dev_priv ) { - unsigned int dirty = buf_priv->dirty; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int dirty = sarea_priv->dirty; if (dev_priv->chipset == MGA_CARD_TYPE_G400) { - if (dirty & MGASAREA_NEW_CONTEXT) - mgaEmitContext( dev_priv, buf_priv ); - - if (dirty & MGASAREA_NEW_TEX1) - mgaG400EmitTex1( dev_priv, buf_priv ); - - if (dirty & MGASAREA_NEW_TEX0) - mgaG400EmitTex0( dev_priv, buf_priv ); - - if (dirty & MGASAREA_NEW_PIPE) - mgaG400EmitPipe( dev_priv, buf_priv ); + int multitex = sarea_priv->WarpPipe & MGA_T2; + + if (sarea_priv->WarpPipe != dev_priv->WarpPipe) { + mgaG400EmitPipe( dev_priv ); + dev_priv->WarpPipe = sarea_priv->WarpPipe; + } + + if (dirty & MGA_UPLOAD_CTX) { + mgaEmitContext( dev_priv ); + sarea_priv->dirty &= ~MGA_UPLOAD_CTX; + } + + if (dirty & MGA_UPLOAD_TEX0) { + mgaG400EmitTex0( dev_priv ); + sarea_priv->dirty &= ~MGA_UPLOAD_TEX0; + } + + if ((dirty & MGA_UPLOAD_TEX1) && multitex) { + mgaG400EmitTex1( dev_priv ); + sarea_priv->dirty &= ~MGA_UPLOAD_TEX1; + } } else { - if (dirty & MGASAREA_NEW_CONTEXT) - mgaEmitContext( dev_priv, buf_priv ); - - if (dirty & MGASAREA_NEW_TEX0) - mgaG200EmitTex( dev_priv, buf_priv ); - - if (dirty & MGASAREA_NEW_PIPE) - mgaG200EmitPipe( dev_priv, buf_priv ); - } + if (sarea_priv->WarpPipe != dev_priv->WarpPipe) { + mgaG200EmitPipe( dev_priv ); + dev_priv->WarpPipe = sarea_priv->WarpPipe; + } + + if (dirty & MGA_UPLOAD_CTX) { + mgaEmitContext( dev_priv ); + sarea_priv->dirty &= ~MGA_UPLOAD_CTX; + } + + if (dirty & MGA_UPLOAD_TEX0) { + mgaG200EmitTex( dev_priv ); + sarea_priv->dirty &= ~MGA_UPLOAD_TEX0; + } + } } - /* Disallow all write destinations except the front and backbuffer. */ -static int mgaCopyContext(drm_mga_private_t *dev_priv, - drm_mga_buf_priv_t *buf_priv) +static int mgaVerifyContext(drm_mga_private_t *dev_priv ) { drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned int *regs = sarea_priv->ContextState; - - if (regs[MGA_CTXREG_DSTORG] != dev_priv->frontOrg && - regs[MGA_CTXREG_DSTORG] != dev_priv->backOrg) + + if (regs[MGA_CTXREG_DSTORG] != dev_priv->frontOffset && + regs[MGA_CTXREG_DSTORG] != dev_priv->backOffset) { + DRM_DEBUG("BAD DSTORG: %x (front %x, back %x)\n\n", + regs[MGA_CTXREG_DSTORG], dev_priv->frontOffset, + dev_priv->backOffset); + regs[MGA_CTXREG_DSTORG] = 0; return -1; + } - memcpy(buf_priv->ContextState, sarea_priv->ContextState, - sizeof(buf_priv->ContextState)); return 0; } - /* Disallow texture reads from PCI space. */ -static int mgaCopyTex(drm_mga_private_t *dev_priv, - drm_mga_buf_priv_t *buf_priv, +static int mgaVerifyTex(drm_mga_private_t *dev_priv, int unit) { drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; - if ((sarea_priv->TexState[unit][MGA_TEXREG_ORG] & 0x3) == 0x1) + if ((sarea_priv->TexState[unit][MGA_TEXREG_ORG] & 0x3) == 0x1) { + DRM_DEBUG("BAD TEXREG_ORG: %x, unit %d\n", + sarea_priv->TexState[unit][MGA_TEXREG_ORG], + unit); + sarea_priv->TexState[unit][MGA_TEXREG_ORG] = 0; return -1; - - memcpy(buf_priv->TexState[unit], sarea_priv->TexState[unit], - sizeof(buf_priv->TexState[0])); + } return 0; } - -int mgaCopyAndVerifyState( drm_mga_private_t *dev_priv, - drm_mga_buf_priv_t *buf_priv ) +static int mgaVerifyState( drm_mga_private_t *dev_priv ) { drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; - unsigned int dirty = sarea_priv->dirty ; + unsigned int dirty = sarea_priv->dirty; int rv = 0; - buf_priv->dirty = sarea_priv->dirty; - buf_priv->WarpPipe = sarea_priv->WarpPipe; + if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS) + sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS; - if (dirty & MGASAREA_NEW_CONTEXT) - rv |= mgaCopyContext( dev_priv, buf_priv ); + if (dirty & MGA_UPLOAD_CTX) + rv |= mgaVerifyContext( dev_priv ); - if (dirty & MGASAREA_NEW_TEX0) - rv |= mgaCopyTex( dev_priv, buf_priv, 0 ); + if (dirty & MGA_UPLOAD_TEX0) + rv |= mgaVerifyTex( dev_priv, 0 ); if (dev_priv->chipset == MGA_CARD_TYPE_G400) { - if (dirty & MGASAREA_NEW_TEX1) - rv |= mgaCopyTex( dev_priv, buf_priv, 1 ); + if (dirty & MGA_UPLOAD_TEX1) + rv |= mgaVerifyTex( dev_priv, 1 ); - if (dirty & MGASAREA_NEW_PIPE) - rv |= (buf_priv->WarpPipe > MGA_MAX_G400_PIPES); + if (dirty & MGA_UPLOAD_PIPE) + rv |= (sarea_priv->WarpPipe > MGA_MAX_G400_PIPES); } else { - if (dirty & MGASAREA_NEW_PIPE) - rv |= (buf_priv->WarpPipe > MGA_MAX_G200_PIPES); + if (dirty & MGA_UPLOAD_PIPE) + rv |= (sarea_priv->WarpPipe > MGA_MAX_G200_PIPES); } return rv == 0; } +static int mgaVerifyIload( drm_mga_private_t *dev_priv, + unsigned long bus_address, + unsigned int dstOrg, int length ) +{ + if(dstOrg < dev_priv->textureOffset || + dstOrg + length > + (dev_priv->textureOffset + dev_priv->textureSize)) { + return -EINVAL; + } + if(length % 64) { + return -EINVAL; + } + return 0; +} + +/* This copies a 64 byte aligned agp region to the frambuffer + * with a standard blit, the ioctl needs to do checking */ + +static void mga_dma_dispatch_tex_blit( drm_device_t *dev, + unsigned long bus_address, + int length, + unsigned int destOrg ) +{ + drm_mga_private_t *dev_priv = dev->dev_private; + int use_agp = PDEA_pagpxfer_enable | 0x00000001; + u16 y2; + PRIMLOCALS; + + y2 = length / 64; + + PRIM_OVERFLOW(dev, dev_priv, 30); + PRIMGETPTR( dev_priv ); + + dev_priv->last_sync_tag = mga_create_sync_tag(dev); + + PRIMOUTREG( MGAREG_DSTORG, destOrg); + PRIMOUTREG( MGAREG_MACCESS, 0x00000000); + DRM_DEBUG("srcorg : %lx\n", bus_address | use_agp); + PRIMOUTREG( MGAREG_SRCORG, (u32) bus_address | use_agp); + PRIMOUTREG( MGAREG_AR5, 64); + + PRIMOUTREG( MGAREG_PITCH, 64); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DWGCTL, MGA_COPY_CMD); + + PRIMOUTREG(MGAREG_AR0, 63); + PRIMOUTREG(MGAREG_AR3, 0); + PRIMOUTREG(MGAREG_FXBNDRY, (63 << 16)); + PRIMOUTREG(MGAREG_YDSTLEN+MGAREG_MGA_EXEC, y2); + + PRIMOUTREG( MGAREG_SRCORG, 0); + PRIMOUTREG( MGAREG_PITCH, dev_priv->stride / dev_priv->cpp); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DWGSYNC, dev_priv->last_sync_tag); + PRIMADVANCE(dev_priv); +} + +static void mga_dma_dispatch_vertex(drm_device_t *dev, + drm_buf_t *buf) +{ + drm_mga_private_t *dev_priv = dev->dev_private; + drm_mga_buf_priv_t *buf_priv = buf->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned long address = (unsigned long)buf->bus_address; + int length = buf->used; + int use_agp = PDEA_pagpxfer_enable; + int i = 0; + int primary_needed; + PRIMLOCALS; + + DRM_DEBUG("dispatch vertex %d addr 0x%lx, " + "length 0x%x nbox %d dirty %x\n", + buf->idx, address, length, + sarea_priv->nbox, sarea_priv->dirty); + + + dev_priv->last_sync_tag = mga_create_sync_tag(dev); + + if (buf_priv->discard) { + buf_priv->my_freelist->age = dev_priv->last_sync_tag; + mga_freelist_put(dev, buf); + } + + + /* WARNING: if you change any of the state functions verify + * these numbers (Overestimating this doesn't hurt). + */ + primary_needed = (25+15+30+25+ + 10 + + 15 * MGA_NR_SAREA_CLIPRECTS); + + + PRIM_OVERFLOW(dev, dev_priv, primary_needed); + mgaEmitState( dev_priv ); + + if (buf->used) { + do { + if (i < sarea_priv->nbox) { + DRM_DEBUG("idx %d Emit box %d/%d:" + "%d,%d - %d,%d\n", + buf->idx, + i, sarea_priv->nbox, + sarea_priv->boxes[i].x1, + sarea_priv->boxes[i].y1, + sarea_priv->boxes[i].x2, + sarea_priv->boxes[i].y2); + + mgaEmitClipRect( dev_priv, + &sarea_priv->boxes[i] ); + } + + PRIMGETPTR(dev_priv); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_SECADDRESS, + ((__u32)address) | TT_VERTEX); + PRIMOUTREG( MGAREG_SECEND, + (((__u32)(address + length)) | + use_agp)); + PRIMADVANCE( dev_priv ); + } while (++i < sarea_priv->nbox); + } + + PRIMGETPTR( dev_priv ); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DWGSYNC, dev_priv->last_sync_tag); + PRIMADVANCE( dev_priv ); +} + +static void mga_dma_dispatch_clear( drm_device_t *dev, int flags, + unsigned int clear_color, + unsigned int clear_zval ) +{ + drm_mga_private_t *dev_priv = dev->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int *regs = sarea_priv->ContextState; + int nbox = sarea_priv->nbox; + drm_clip_rect_t *pbox = sarea_priv->boxes; + unsigned int cmd; + int i; + int primary_needed; + PRIMLOCALS; + + if ( dev_priv->sgram ) + cmd = MGA_CLEAR_CMD | DC_atype_blk; + else + cmd = MGA_CLEAR_CMD | DC_atype_rstr; + + primary_needed = nbox * 70; + if(primary_needed == 0) primary_needed = 70; + PRIM_OVERFLOW(dev, dev_priv, primary_needed); + PRIMGETPTR( dev_priv ); + dev_priv->last_sync_tag = mga_create_sync_tag(dev); + + for (i = 0 ; i < nbox ; i++) { + unsigned int height = pbox[i].y2 - pbox[i].y1; + + DRM_DEBUG("dispatch clear %d,%d-%d,%d flags %x!\n", + pbox[i].x1, pbox[i].y1, pbox[i].x2, + pbox[i].y2, flags); + + if ( flags & MGA_FRONT ) { + DRM_DEBUG("clear front\n"); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_YDSTLEN, (pbox[i].y1<<16)|height); + PRIMOUTREG(MGAREG_FXBNDRY, (pbox[i].x2<<16)|pbox[i].x1); + + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_FCOL, clear_color); + PRIMOUTREG(MGAREG_DSTORG, dev_priv->frontOffset); + PRIMOUTREG(MGAREG_DWGCTL+MGAREG_MGA_EXEC, cmd ); + } + + if ( flags & MGA_BACK ) { + DRM_DEBUG("clear back\n"); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_YDSTLEN, (pbox[i].y1<<16)|height); + PRIMOUTREG(MGAREG_FXBNDRY, (pbox[i].x2<<16)|pbox[i].x1); + + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_FCOL, clear_color); + PRIMOUTREG(MGAREG_DSTORG, dev_priv->backOffset); + PRIMOUTREG(MGAREG_DWGCTL+MGAREG_MGA_EXEC, cmd ); + } + + if ( flags & MGA_DEPTH ) { + DRM_DEBUG("clear depth\n"); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_YDSTLEN, (pbox[i].y1<<16)|height); + PRIMOUTREG(MGAREG_FXBNDRY, (pbox[i].x2<<16)|pbox[i].x1); + + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_FCOL, clear_zval); + PRIMOUTREG(MGAREG_DSTORG, dev_priv->depthOffset); + PRIMOUTREG(MGAREG_DWGCTL+MGAREG_MGA_EXEC, cmd ); + } + } + + /* Force reset of DWGCTL */ + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL] ); + + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DWGSYNC, dev_priv->last_sync_tag); + PRIMADVANCE(dev_priv); +} + +static void mga_dma_dispatch_swap( drm_device_t *dev ) +{ + drm_mga_private_t *dev_priv = dev->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int *regs = sarea_priv->ContextState; + int nbox = sarea_priv->nbox; + drm_clip_rect_t *pbox = sarea_priv->boxes; + int i; + int primary_needed; + PRIMLOCALS; + + primary_needed = nbox * 5; + primary_needed += 60; + PRIM_OVERFLOW(dev, dev_priv, primary_needed); + PRIMGETPTR( dev_priv ); + + dev_priv->last_sync_tag = mga_create_sync_tag(dev); + + PRIMOUTREG(MGAREG_DSTORG, dev_priv->frontOffset); + PRIMOUTREG(MGAREG_MACCESS, dev_priv->mAccess); + PRIMOUTREG(MGAREG_SRCORG, dev_priv->backOffset); + PRIMOUTREG(MGAREG_AR5, dev_priv->stride/2); + + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DWGCTL, MGA_COPY_CMD); + + for (i = 0 ; i < nbox; i++) { + unsigned int h = pbox[i].y2 - pbox[i].y1; + unsigned int start = pbox[i].y1 * dev_priv->stride/2; + + DRM_DEBUG("dispatch swap %d,%d-%d,%d!\n", + pbox[i].x1, pbox[i].y1, + pbox[i].x2, pbox[i].y2); + + PRIMOUTREG(MGAREG_AR0, start + pbox[i].x2 - 1); + PRIMOUTREG(MGAREG_AR3, start + pbox[i].x1); + PRIMOUTREG(MGAREG_FXBNDRY, pbox[i].x1|((pbox[i].x2 - 1)<<16)); + PRIMOUTREG(MGAREG_YDSTLEN+MGAREG_MGA_EXEC, (pbox[i].y1<<16)|h); + } + + /* Force reset of DWGCTL */ + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL] ); + + PRIMOUTREG( MGAREG_SRCORG, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DWGSYNC, dev_priv->last_sync_tag); + PRIMADVANCE(dev_priv); +} + +int mga_clear_bufs(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_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + __volatile__ unsigned int *status = + (__volatile__ unsigned int *)dev_priv->status_page; + drm_mga_clear_t clear; + + copy_from_user_ret(&clear, (drm_mga_clear_t *)arg, sizeof(clear), + -EFAULT); + + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("mga_clear_bufs called without lock held\n"); + return -EINVAL; + } + + if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS) + sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS; + + /* Make sure we restore the 3D state next time. + */ + dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CTX; + mga_dma_dispatch_clear( dev, clear.flags, + clear.clear_color, + clear.clear_depth ); + PRIMUPDATE(dev_priv); + mga_dma_schedule(dev, 1); + sarea_priv->last_dispatch = status[1]; + return 0; +} + +int mga_swap_bufs(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_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + __volatile__ unsigned int *status = + (__volatile__ unsigned int *)dev_priv->status_page; + + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("mga_swap_bufs called without lock held\n"); + return -EINVAL; + } + + if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS) + sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS; + + /* Make sure we restore the 3D state next time. + */ + dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CTX; + mga_dma_dispatch_swap( dev ); + PRIMUPDATE(dev_priv); + set_bit(0, &dev_priv->current_prim->swap_pending); + dev_priv->current_prim->swap_pending = 1; + mga_dma_schedule(dev, 1); + sarea_priv->last_dispatch = status[1]; + return 0; +} + +int mga_iload(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_device_dma_t *dma = dev->dma; + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + __volatile__ unsigned int *status = + (__volatile__ unsigned int *)dev_priv->status_page; + drm_buf_t *buf; + drm_mga_buf_priv_t *buf_priv; + drm_mga_iload_t iload; + unsigned long bus_address; + + DRM_DEBUG("Starting Iload\n"); + copy_from_user_ret(&iload, (drm_mga_iload_t *)arg, sizeof(iload), + -EFAULT); + + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("mga_iload called without lock held\n"); + return -EINVAL; + } + + buf = dma->buflist[ iload.idx ]; + buf_priv = buf->dev_private; + bus_address = buf->bus_address; + DRM_DEBUG("bus_address %lx, length %d, destorg : %x\n", + bus_address, iload.length, iload.destOrg); + + if(mgaVerifyIload(dev_priv, + bus_address, + iload.destOrg, + iload.length)) { + mga_freelist_put(dev, buf); + return -EINVAL; + } + + sarea_priv->dirty |= MGA_UPLOAD_CTX; + + mga_dma_dispatch_tex_blit(dev, bus_address, iload.length, + iload.destOrg); + buf_priv->my_freelist->age = dev_priv->last_sync_tag; + buf_priv->discard = 1; + mga_freelist_put(dev, buf); + mga_dma_schedule(dev, 1); + sarea_priv->last_dispatch = status[1]; + return 0; +} + +int mga_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_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + __volatile__ unsigned int *status = + (__volatile__ unsigned int *)dev_priv->status_page; + drm_device_dma_t *dma = dev->dma; + drm_buf_t *buf; + drm_mga_buf_priv_t *buf_priv; + drm_mga_vertex_t vertex; + + copy_from_user_ret(&vertex, (drm_mga_vertex_t *)arg, sizeof(vertex), + -EFAULT); + + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("mga_vertex called without lock held\n"); + return -EINVAL; + } + + DRM_DEBUG("mga_vertex\n"); + + buf = dma->buflist[ vertex.idx ]; + buf_priv = buf->dev_private; + + buf->used = vertex.used; + buf_priv->discard = vertex.discard; + + if (!mgaVerifyState(dev_priv)) { + if (vertex.discard) { + buf_priv->my_freelist->age = dev_priv->last_sync_tag; + mga_freelist_put(dev, buf); + } + return -EINVAL; + } + + mga_dma_dispatch_vertex(dev, buf); + + PRIMUPDATE(dev_priv); + mga_dma_schedule(dev, 1); + sarea_priv->last_dispatch = status[1]; + return 0; +} + +static int mga_dma_get_buffers(drm_device_t *dev, drm_dma_t *d) +{ + int i; + drm_buf_t *buf; + + for (i = d->granted_count; i < d->request_count; i++) { + buf = mga_freelist_get(dev); + if (!buf) break; + buf->pid = current->pid; + copy_to_user_ret(&d->request_indices[i], + &buf->idx, + sizeof(buf->idx), + -EFAULT); + copy_to_user_ret(&d->request_sizes[i], + &buf->total, + sizeof(buf->total), + -EFAULT); + ++d->granted_count; + } + return 0; +} + +int mga_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_device_dma_t *dma = dev->dma; + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + __volatile__ unsigned int *status = + (__volatile__ unsigned int *)dev_priv->status_page; + int retcode = 0; + drm_dma_t d; + + copy_from_user_ret(&d, (drm_dma_t *)arg, sizeof(d), -EFAULT); + DRM_DEBUG("%d %d: %d send, %d req\n", + current->pid, d.context, d.send_count, d.request_count); + + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("mga_dma called without lock held\n"); + return -EINVAL; + } + + /* Please don't send us buffers. + */ + if (d.send_count != 0) { + DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n", + current->pid, d.send_count); + return -EINVAL; + } + + /* We'll send you buffers. + */ + 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; + } + + d.granted_count = 0; + + if (d.request_count) { + retcode = mga_dma_get_buffers(dev, &d); + } + + DRM_DEBUG("%d returning, granted = %d\n", + current->pid, d.granted_count); + copy_to_user_ret((drm_dma_t *)arg, &d, sizeof(d), -EFAULT); + sarea_priv->last_dispatch = status[1]; + return retcode; +} diff --git a/linux/mga_state.h b/linux/mga_state.h deleted file mode 100644 index e7b952e0c..000000000 --- a/linux/mga_state.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef MGA_STATE_H -#define MGA_STATE_H - -#include "mga_drv.h" - -int mgaCopyAndVerifyState( drm_mga_private_t *dev_priv, - drm_mga_buf_priv_t *buf_priv ); - -void mgaEmitClipRect( drm_mga_private_t *dev_priv, xf86drmClipRectRec *box ); - -void mgaEmitState( drm_mga_private_t *dev_priv, drm_mga_buf_priv_t *buf_priv ); - -#endif diff --git a/linux/mgareg_flags.h b/linux/mgareg_flags.h deleted file mode 100644 index 901f18310..000000000 --- a/linux/mgareg_flags.h +++ /dev/null @@ -1,930 +0,0 @@ -/* author: stephen crowley, crow@debian.org */ - -/* - * 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 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 - * STEPHEN CROWLEY, OR ANY OTHER CONTRIBUTORS 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. - */ - -#ifndef _MGAREGS_H_ -#define _MGAREGS_H_ - -/*************** (START) AUTOMATICLY GENERATED REGISTER FILE *****************/ -/* - * Generated on Sat Nov 20 21:25:36 CST 1999 - */ - - - -/* - * Power Graphic Mode Memory Space Registers - */ - - #define AGP_PLL_agp2xpllen_MASK 0xfffffffe /* bit 0 */ - #define AGP_PLL_agp2xpllen_disable 0x0 - #define AGP_PLL_agp2xpllen_enable 0x1 - - #define AC_src_MASK 0xfffffff0 /* bits 0-3 */ - #define AC_src_zero 0x0 /* val 0, shift 0 */ - #define AC_src_one 0x1 /* val 1, shift 0 */ - #define AC_src_dst_color 0x2 /* val 2, shift 0 */ - #define AC_src_om_dst_color 0x3 /* val 3, shift 0 */ - #define AC_src_src_alpha 0x4 /* val 4, shift 0 */ - #define AC_src_om_src_alpha 0x5 /* val 5, shift 0 */ - #define AC_src_dst_alpha 0x6 /* val 6, shift 0 */ - #define AC_src_om_dst_alpha 0x7 /* val 7, shift 0 */ - #define AC_src_src_alpha_sat 0x8 /* val 8, shift 0 */ - #define AC_dst_MASK 0xffffff0f /* bits 4-7 */ - #define AC_dst_zero 0x0 /* val 0, shift 4 */ - #define AC_dst_one 0x10 /* val 1, shift 4 */ - #define AC_dst_src_color 0x20 /* val 2, shift 4 */ - #define AC_dst_om_src_color 0x30 /* val 3, shift 4 */ - #define AC_dst_src_alpha 0x40 /* val 4, shift 4 */ - #define AC_dst_om_src_alpha 0x50 /* val 5, shift 4 */ - #define AC_dst_dst_alpha 0x60 /* val 6, shift 4 */ - #define AC_dst_om_dst_alpha 0x70 /* val 7, shift 4 */ - #define AC_amode_MASK 0xfffffcff /* bits 8-9 */ - #define AC_amode_FCOL 0x0 /* val 0, shift 8 */ - #define AC_amode_alpha_channel 0x100 /* val 1, shift 8 */ - #define AC_amode_video_alpha 0x200 /* val 2, shift 8 */ - #define AC_amode_RSVD 0x300 /* val 3, shift 8 */ - #define AC_astipple_MASK 0xfffff7ff /* bit 11 */ - #define AC_astipple_disable 0x0 - #define AC_astipple_enable 0x800 - #define AC_aten_MASK 0xffffefff /* bit 12 */ - #define AC_aten_disable 0x0 - #define AC_aten_enable 0x1000 - #define AC_atmode_MASK 0xffff1fff /* bits 13-15 */ - #define AC_atmode_noacmp 0x0 /* val 0, shift 13 */ - #define AC_atmode_ae 0x4000 /* val 2, shift 13 */ - #define AC_atmode_ane 0x6000 /* val 3, shift 13 */ - #define AC_atmode_alt 0x8000 /* val 4, shift 13 */ - #define AC_atmode_alte 0xa000 /* val 5, shift 13 */ - #define AC_atmode_agt 0xc000 /* val 6, shift 13 */ - #define AC_atmode_agte 0xe000 /* val 7, shift 13 */ - #define AC_atref_MASK 0xff00ffff /* bits 16-23 */ - #define AC_atref_SHIFT 16 - #define AC_alphasel_MASK 0xfcffffff /* bits 24-25 */ - #define AC_alphasel_fromtex 0x0 /* val 0, shift 24 */ - #define AC_alphasel_diffused 0x1000000 /* val 1, shift 24 */ - #define AC_alphasel_modulated 0x2000000 /* val 2, shift 24 */ - #define AC_alphasel_trans 0x3000000 /* val 3, shift 24 */ - - #define AR0_ar0_MASK 0xfffc0000 /* bits 0-17 */ - #define AR0_ar0_SHIFT 0 - - #define AR1_ar1_MASK 0xff000000 /* bits 0-23 */ - #define AR1_ar1_SHIFT 0 - - #define AR2_ar2_MASK 0xfffc0000 /* bits 0-17 */ - #define AR2_ar2_SHIFT 0 - - #define AR3_ar3_MASK 0xff000000 /* bits 0-23 */ - #define AR3_ar3_SHIFT 0 - #define AR3_spage_MASK 0xf8ffffff /* bits 24-26 */ - #define AR3_spage_SHIFT 24 - - #define AR4_ar4_MASK 0xfffc0000 /* bits 0-17 */ - #define AR4_ar4_SHIFT 0 - - #define AR5_ar5_MASK 0xfffc0000 /* bits 0-17 */ - #define AR5_ar5_SHIFT 0 - - #define AR6_ar6_MASK 0xfffc0000 /* bits 0-17 */ - #define AR6_ar6_SHIFT 0 - - #define BC_besen_MASK 0xfffffffe /* bit 0 */ - #define BC_besen_disable 0x0 - #define BC_besen_enable 0x1 - #define BC_besv1srcstp_MASK 0xffffffbf /* bit 6 */ - #define BC_besv1srcstp_even 0x0 - #define BC_besv1srcstp_odd 0x40 - #define BC_besv2srcstp_MASK 0xfffffeff /* bit 8 */ - #define BC_besv2srcstp_disable 0x0 - #define BC_besv2srcstp_enable 0x100 - #define BC_beshfen_MASK 0xfffffbff /* bit 10 */ - #define BC_beshfen_disable 0x0 - #define BC_beshfen_enable 0x400 - #define BC_besvfen_MASK 0xfffff7ff /* bit 11 */ - #define BC_besvfen_disable 0x0 - #define BC_besvfen_enable 0x800 - #define BC_beshfixc_MASK 0xffffefff /* bit 12 */ - #define BC_beshfixc_weight 0x0 - #define BC_beshfixc_coeff 0x1000 - #define BC_bescups_MASK 0xfffeffff /* bit 16 */ - #define BC_bescups_disable 0x0 - #define BC_bescups_enable 0x10000 - #define BC_bes420pl_MASK 0xfffdffff /* bit 17 */ - #define BC_bes420pl_422 0x0 - #define BC_bes420pl_420 0x20000 - #define BC_besdith_MASK 0xfffbffff /* bit 18 */ - #define BC_besdith_disable 0x0 - #define BC_besdith_enable 0x40000 - #define BC_beshmir_MASK 0xfff7ffff /* bit 19 */ - #define BC_beshmir_disable 0x0 - #define BC_beshmir_enable 0x80000 - #define BC_besbwen_MASK 0xffefffff /* bit 20 */ - #define BC_besbwen_color 0x0 - #define BC_besbwen_bw 0x100000 - #define BC_besblank_MASK 0xffdfffff /* bit 21 */ - #define BC_besblank_disable 0x0 - #define BC_besblank_enable 0x200000 - #define BC_besfselm_MASK 0xfeffffff /* bit 24 */ - #define BC_besfselm_soft 0x0 - #define BC_besfselm_hard 0x1000000 - #define BC_besfsel_MASK 0xf9ffffff /* bits 25-26 */ - #define BC_besfsel_a1 0x0 /* val 0, shift 25 */ - #define BC_besfsel_a2 0x2000000 /* val 1, shift 25 */ - #define BC_besfsel_b1 0x4000000 /* val 2, shift 25 */ - #define BC_besfsel_b2 0x6000000 /* val 3, shift 25 */ - - #define BGC_beshzoom_MASK 0xfffffffe /* bit 0 */ - #define BGC_beshzoom_disable 0x0 - #define BGC_beshzoom_enable 0x1 - #define BGC_beshzoomf_MASK 0xfffffffd /* bit 1 */ - #define BGC_beshzoomf_disable 0x0 - #define BGC_beshzoomf_enable 0x2 - #define BGC_bescorder_MASK 0xfffffff7 /* bit 3 */ - #define BGC_bescorder_even 0x0 - #define BGC_bescorder_odd 0x8 - #define BGC_besreghup_MASK 0xffffffef /* bit 4 */ - #define BGC_besreghup_disable 0x0 - #define BGC_besreghup_enable 0x10 - #define BGC_besvcnt_MASK 0xf000ffff /* bits 16-27 */ - #define BGC_besvcnt_SHIFT 16 - - #define BHC_besright_MASK 0xfffff800 /* bits 0-10 */ - #define BHC_besright_SHIFT 0 - #define BHC_besleft_MASK 0xf800ffff /* bits 16-26 */ - #define BHC_besleft_SHIFT 16 - - #define BHISF_beshiscal_MASK 0xffe00003 /* bits 2-20 */ - #define BHISF_beshiscal_SHIFT 2 - - #define BHSE_beshsrcend_MASK 0xfc000003 /* bits 2-25 */ - #define BHSE_beshsrcend_SHIFT 2 - - #define BHSL_beshsrclst_MASK 0xfc00ffff /* bits 16-25 */ - #define BHSL_beshsrclst_SHIFT 16 - - #define BHSS_beshsrcst_MASK 0xfc000003 /* bits 2-25 */ - #define BHSS_beshsrcst_SHIFT 2 - - #define BP_bespitch_MASK 0xfffff000 /* bits 0-11 */ - #define BP_bespitch_SHIFT 0 - - #define BS_besstat_MASK 0xfffffffc /* bits 0-1 */ - #define BS_besstat_a1 0x0 /* val 0, shift 0 */ - #define BS_besstat_a2 0x1 /* val 1, shift 0 */ - #define BS_besstat_b1 0x2 /* val 2, shift 0 */ - #define BS_besstat_b2 0x3 /* val 3, shift 0 */ - - #define BSF_besv1srclast_MASK 0xfffffc00 /* bits 0-9 */ - #define BSF_besv1srclast_SHIFT 0 - - #define BSF_besv2srclst_MASK 0xfffffc00 /* bits 0-9 */ - #define BSF_besv2srclst_SHIFT 0 - - #define BSF_besv1wght_MASK 0xffff0003 /* bits 2-15 */ - #define BSF_besv1wght_SHIFT 2 - #define BSF_besv1wghts_MASK 0xfffeffff /* bit 16 */ - #define BSF_besv1wghts_disable 0x0 - #define BSF_besv1wghts_enable 0x10000 - - #define BSF_besv2wght_MASK 0xffff0003 /* bits 2-15 */ - #define BSF_besv2wght_SHIFT 2 - #define BSF_besv2wghts_MASK 0xfffeffff /* bit 16 */ - #define BSF_besv2wghts_disable 0x0 - #define BSF_besv2wghts_enable 0x10000 - - #define BVC_besbot_MASK 0xfffff800 /* bits 0-10 */ - #define BVC_besbot_SHIFT 0 - #define BVC_bestop_MASK 0xf800ffff /* bits 16-26 */ - #define BVC_bestop_SHIFT 16 - - #define BVISF_besviscal_MASK 0xffe00003 /* bits 2-20 */ - #define BVISF_besviscal_SHIFT 2 - - #define CXB_cxleft_MASK 0xfffff000 /* bits 0-11 */ - #define CXB_cxleft_SHIFT 0 - #define CXB_cxright_MASK 0xf000ffff /* bits 16-27 */ - #define CXB_cxright_SHIFT 16 - - #define DO_dstmap_MASK 0xfffffffe /* bit 0 */ - #define DO_dstmap_fb 0x0 - #define DO_dstmap_sys 0x1 - #define DO_dstacc_MASK 0xfffffffd /* bit 1 */ - #define DO_dstacc_pci 0x0 - #define DO_dstacc_agp 0x2 - #define DO_dstorg_MASK 0x7 /* bits 3-31 */ - #define DO_dstorg_SHIFT 3 - - #define DC_opcod_MASK 0xfffffff0 /* bits 0-3 */ - #define DC_opcod_line_open 0x0 /* val 0, shift 0 */ - #define DC_opcod_autoline_open 0x1 /* val 1, shift 0 */ - #define DC_opcod_line_close 0x2 /* val 2, shift 0 */ - #define DC_opcod_autoline_close 0x3 /* val 3, shift 0 */ - #define DC_opcod_trap 0x4 /* val 4, shift 0 */ - #define DC_opcod_texture_trap 0x6 /* val 6, shift 0 */ - #define DC_opcod_bitblt 0x8 /* val 8, shift 0 */ - #define DC_opcod_iload 0x9 /* val 9, shift 0 */ - #define DC_atype_MASK 0xffffff8f /* bits 4-6 */ - #define DC_atype_rpl 0x0 /* val 0, shift 4 */ - #define DC_atype_rstr 0x10 /* val 1, shift 4 */ - #define DC_atype_zi 0x30 /* val 3, shift 4 */ - #define DC_atype_blk 0x40 /* val 4, shift 4 */ - #define DC_atype_i 0x70 /* val 7, shift 4 */ - #define DC_linear_MASK 0xffffff7f /* bit 7 */ - #define DC_linear_xy 0x0 - #define DC_linear_linear 0x80 - #define DC_zmode_MASK 0xfffff8ff /* bits 8-10 */ - #define DC_zmode_nozcmp 0x0 /* val 0, shift 8 */ - #define DC_zmode_ze 0x200 /* val 2, shift 8 */ - #define DC_zmode_zne 0x300 /* val 3, shift 8 */ - #define DC_zmode_zlt 0x400 /* val 4, shift 8 */ - #define DC_zmode_zlte 0x500 /* val 5, shift 8 */ - #define DC_zmode_zgt 0x600 /* val 6, shift 8 */ - #define DC_zmode_zgte 0x700 /* val 7, shift 8 */ - #define DC_solid_MASK 0xfffff7ff /* bit 11 */ - #define DC_solid_disable 0x0 - #define DC_solid_enable 0x800 - #define DC_arzero_MASK 0xffffefff /* bit 12 */ - #define DC_arzero_disable 0x0 - #define DC_arzero_enable 0x1000 - #define DC_sgnzero_MASK 0xffffdfff /* bit 13 */ - #define DC_sgnzero_disable 0x0 - #define DC_sgnzero_enable 0x2000 - #define DC_shftzero_MASK 0xffffbfff /* bit 14 */ - #define DC_shftzero_disable 0x0 - #define DC_shftzero_enable 0x4000 - #define DC_bop_MASK 0xfff0ffff /* bits 16-19 */ - #define DC_bop_SHIFT 16 - #define DC_trans_MASK 0xff0fffff /* bits 20-23 */ - #define DC_trans_SHIFT 20 - #define DC_bltmod_MASK 0xe1ffffff /* bits 25-28 */ - #define DC_bltmod_bmonolef 0x0 /* val 0, shift 25 */ - #define DC_bltmod_bmonowf 0x8000000 /* val 4, shift 25 */ - #define DC_bltmod_bplan 0x2000000 /* val 1, shift 25 */ - #define DC_bltmod_bfcol 0x4000000 /* val 2, shift 25 */ - #define DC_bltmod_bu32bgr 0x6000000 /* val 3, shift 25 */ - #define DC_bltmod_bu32rgb 0xe000000 /* val 7, shift 25 */ - #define DC_bltmod_bu24bgr 0x16000000 /* val 11, shift 25 */ - #define DC_bltmod_bu24rgb 0x1e000000 /* val 15, shift 25 */ - #define DC_pattern_MASK 0xdfffffff /* bit 29 */ - #define DC_pattern_disable 0x0 - #define DC_pattern_enable 0x20000000 - #define DC_transc_MASK 0xbfffffff /* bit 30 */ - #define DC_transc_disable 0x0 - #define DC_transc_enable 0x40000000 - #define DC_clipdis_MASK 0x7fffffff /* bit 31 */ - #define DC_clipdis_disable 0x0 - #define DC_clipdis_enable 0x80000000 - - #define DS_dwgsyncaddr_MASK 0x3 /* bits 2-31 */ - #define DS_dwgsyncaddr_SHIFT 2 - - #define FS_fifocount_MASK 0xffffff80 /* bits 0-6 */ - #define FS_fifocount_SHIFT 0 - #define FS_bfull_MASK 0xfffffeff /* bit 8 */ - #define FS_bfull_disable 0x0 - #define FS_bfull_enable 0x100 - #define FS_bempty_MASK 0xfffffdff /* bit 9 */ - #define FS_bempty_disable 0x0 - #define FS_bempty_enable 0x200 - - #define XA_fxleft_MASK 0xffff0000 /* bits 0-15 */ - #define XA_fxleft_SHIFT 0 - #define XA_fxright_MASK 0xffff /* bits 16-31 */ - #define XA_fxright_SHIFT 16 - - #define IC_softrapiclr_MASK 0xfffffffe /* bit 0 */ - #define IC_softrapiclr_disable 0x0 - #define IC_softrapiclr_enable 0x1 - #define IC_pickiclr_MASK 0xfffffffb /* bit 2 */ - #define IC_pickiclr_disable 0x0 - #define IC_pickiclr_enable 0x4 - #define IC_vlineiclr_MASK 0xffffffdf /* bit 5 */ - #define IC_vlineiclr_disable 0x0 - #define IC_vlineiclr_enable 0x20 - #define IC_wiclr_MASK 0xffffff7f /* bit 7 */ - #define IC_wiclr_disable 0x0 - #define IC_wiclr_enable 0x80 - #define IC_wciclr_MASK 0xfffffeff /* bit 8 */ - #define IC_wciclr_disable 0x0 - #define IC_wciclr_enable 0x100 - - #define IE_softrapien_MASK 0xfffffffe /* bit 0 */ - #define IE_softrapien_disable 0x0 - #define IE_softrapien_enable 0x1 - #define IE_pickien_MASK 0xfffffffb /* bit 2 */ - #define IE_pickien_disable 0x0 - #define IE_pickien_enable 0x4 - #define IE_vlineien_MASK 0xffffffdf /* bit 5 */ - #define IE_vlineien_disable 0x0 - #define IE_vlineien_enable 0x20 - #define IE_extien_MASK 0xffffffbf /* bit 6 */ - #define IE_extien_disable 0x0 - #define IE_extien_enable 0x40 - #define IE_wien_MASK 0xffffff7f /* bit 7 */ - #define IE_wien_disable 0x0 - #define IE_wien_enable 0x80 - #define IE_wcien_MASK 0xfffffeff /* bit 8 */ - #define IE_wcien_disable 0x0 - #define IE_wcien_enable 0x100 - - #define MA_pwidth_MASK 0xfffffffc /* bits 0-1 */ - #define MA_pwidth_8 0x0 /* val 0, shift 0 */ - #define MA_pwidth_16 0x1 /* val 1, shift 0 */ - #define MA_pwidth_32 0x2 /* val 2, shift 0 */ - #define MA_pwidth_24 0x3 /* val 3, shift 0 */ - #define MA_zwidth_MASK 0xffffffe7 /* bits 3-4 */ - #define MA_zwidth_16 0x0 /* val 0, shift 3 */ - #define MA_zwidth_32 0x8 /* val 1, shift 3 */ - #define MA_zwidth_15 0x10 /* val 2, shift 3 */ - #define MA_zwidth_24 0x18 /* val 3, shift 3 */ - #define MA_memreset_MASK 0xffff7fff /* bit 15 */ - #define MA_memreset_disable 0x0 - #define MA_memreset_enable 0x8000 - #define MA_fogen_MASK 0xfbffffff /* bit 26 */ - #define MA_fogen_disable 0x0 - #define MA_fogen_enable 0x4000000 - #define MA_tlutload_MASK 0xdfffffff /* bit 29 */ - #define MA_tlutload_disable 0x0 - #define MA_tlutload_enable 0x20000000 - #define MA_nodither_MASK 0xbfffffff /* bit 30 */ - #define MA_nodither_disable 0x0 - #define MA_nodither_enable 0x40000000 - #define MA_dit555_MASK 0x7fffffff /* bit 31 */ - #define MA_dit555_disable 0x0 - #define MA_dit555_enable 0x80000000 - - #define MCWS_casltncy_MASK 0xfffffff8 /* bits 0-2 */ - #define MCWS_casltncy_SHIFT 0 - #define MCWS_rrddelay_MASK 0xffffffcf /* bits 4-5 */ - #define MCWS_rcddelay_MASK 0xfffffe7f /* bits 7-8 */ - #define MCWS_rasmin_MASK 0xffffe3ff /* bits 10-12 */ - #define MCWS_rasmin_SHIFT 10 - #define MCWS_rpdelay_MASK 0xffff3fff /* bits 14-15 */ - #define MCWS_wrdelay_MASK 0xfff3ffff /* bits 18-19 */ - #define MCWS_rddelay_MASK 0xffdfffff /* bit 21 */ - #define MCWS_rddelay_disable 0x0 - #define MCWS_rddelay_enable 0x200000 - #define MCWS_smrdelay_MASK 0xfe7fffff /* bits 23-24 */ - #define MCWS_bwcdelay_MASK 0xf3ffffff /* bits 26-27 */ - #define MCWS_bpldelay_MASK 0x1fffffff /* bits 29-31 */ - #define MCWS_bpldelay_SHIFT 29 - - #define MRB_mclkbrd0_MASK 0xfffffff0 /* bits 0-3 */ - #define MRB_mclkbrd0_SHIFT 0 - #define MRB_mclkbrd1_MASK 0xfffffe1f /* bits 5-8 */ - #define MRB_mclkbrd1_SHIFT 5 - #define MRB_strmfctl_MASK 0xff3fffff /* bits 22-23 */ - #define MRB_mrsopcod_MASK 0xe1ffffff /* bits 25-28 */ - #define MRB_mrsopcod_SHIFT 25 - - #define OM_dmamod_MASK 0xfffffff3 /* bits 2-3 */ - #define OM_dmamod_general 0x0 /* val 0, shift 2 */ - #define OM_dmamod_blit 0x4 /* val 1, shift 2 */ - #define OM_dmamod_vector 0x8 /* val 2, shift 2 */ - #define OM_dmamod_vertex 0xc /* val 3, shift 2 */ - #define OM_dmadatasiz_MASK 0xfffffcff /* bits 8-9 */ - #define OM_dmadatasiz_8 0x0 /* val 0, shift 8 */ - #define OM_dmadatasiz_16 0x100 /* val 1, shift 8 */ - #define OM_dmadatasiz_32 0x200 /* val 2, shift 8 */ - #define OM_dirdatasiz_MASK 0xfffcffff /* bits 16-17 */ - #define OM_dirdatasiz_8 0x0 /* val 0, shift 16 */ - #define OM_dirdatasiz_16 0x10000 /* val 1, shift 16 */ - #define OM_dirdatasiz_32 0x20000 /* val 2, shift 16 */ - - #define P_iy_MASK 0xffffe000 /* bits 0-12 */ - #define P_iy_SHIFT 0 - #define P_ylin_MASK 0xffff7fff /* bit 15 */ - #define P_ylin_disable 0x0 - #define P_ylin_enable 0x8000 - - #define PDCA_primod_MASK 0xfffffffc /* bits 0-1 */ - #define PDCA_primod_general 0x0 /* val 0, shift 0 */ - #define PDCA_primod_blit 0x1 /* val 1, shift 0 */ - #define PDCA_primod_vector 0x2 /* val 2, shift 0 */ - #define PDCA_primod_vertex 0x3 /* val 3, shift 0 */ - #define PDCA_primaddress_MASK 0x3 /* bits 2-31 */ - #define PDCA_primaddress_SHIFT 2 - - #define PDEA_primnostart_MASK 0xfffffffe /* bit 0 */ - #define PDEA_primnostart_disable 0x0 - #define PDEA_primnostart_enable 0x1 - #define PDEA_pagpxfer_MASK 0xfffffffd /* bit 1 */ - #define PDEA_pagpxfer_disable 0x0 - #define PDEA_pagpxfer_enable 0x2 - #define PDEA_primend_MASK 0x3 /* bits 2-31 */ - #define PDEA_primend_SHIFT 2 - - #define PLS_primptren0_MASK 0xfffffffe /* bit 0 */ - #define PLS_primptren0_disable 0x0 - #define PLS_primptren0_enable 0x1 - #define PLS_primptren1_MASK 0xfffffffd /* bit 1 */ - #define PLS_primptren1_disable 0x0 - #define PLS_primptren1_enable 0x2 - #define PLS_primptr_MASK 0x7 /* bits 3-31 */ - #define PLS_primptr_SHIFT 3 - - #define R_softreset_MASK 0xfffffffe /* bit 0 */ - #define R_softreset_disable 0x0 - #define R_softreset_enable 0x1 - #define R_softextrst_MASK 0xfffffffd /* bit 1 */ - #define R_softextrst_disable 0x0 - #define R_softextrst_enable 0x2 - - #define SDCA_secmod_MASK 0xfffffffc /* bits 0-1 */ - #define SDCA_secmod_general 0x0 /* val 0, shift 0 */ - #define SDCA_secmod_blit 0x1 /* val 1, shift 0 */ - #define SDCA_secmod_vector 0x2 /* val 2, shift 0 */ - #define SDCA_secmod_vertex 0x3 /* val 3, shift 0 */ - #define SDCA_secaddress_MASK 0x3 /* bits 2-31 */ - #define SDCA_secaddress_SHIFT 2 - - #define SDEA_sagpxfer_MASK 0xfffffffd /* bit 1 */ - #define SDEA_sagpxfer_disable 0x0 - #define SDEA_sagpxfer_enable 0x2 - #define SDEA_secend_MASK 0x3 /* bits 2-31 */ - #define SDEA_secend_SHIFT 2 - - #define SETDCA_setupmod_MASK 0xfffffffc /* bits 0-1 */ - #define SETDCA_setupmod_vertlist 0x0 /* val 0, shift 0 */ - #define SETDCA_setupaddress_MASK 0x3 /* bits 2-31 */ - #define SETDCA_setupaddress_SHIFT 2 - - #define SETDEA_setupagpxfer_MASK 0xfffffffd /* bit 1 */ - #define SETDEA_setupagpxfer_disable 0x0 - #define SETDEA_setupagpxfer_enable 0x2 - #define SETDEA_setupend_MASK 0x3 /* bits 2-31 */ - #define SETDEA_setupend_SHIFT 2 - - #define S_sdydxl_MASK 0xfffffffe /* bit 0 */ - #define S_sdydxl_y 0x0 - #define S_sdydxl_x 0x1 - #define S_scanleft_MASK 0xfffffffe /* bit 0 */ - #define S_scanleft_disable 0x0 - #define S_scanleft_enable 0x1 - #define S_sdxl_MASK 0xfffffffd /* bit 1 */ - #define S_sdxl_pos 0x0 - #define S_sdxl_neg 0x2 - #define S_sdy_MASK 0xfffffffb /* bit 2 */ - #define S_sdy_pos 0x0 - #define S_sdy_neg 0x4 - #define S_sdxr_MASK 0xffffffdf /* bit 5 */ - #define S_sdxr_pos 0x0 - #define S_sdxr_neg 0x20 - #define S_brkleft_MASK 0xfffffeff /* bit 8 */ - #define S_brkleft_disable 0x0 - #define S_brkleft_enable 0x100 - #define S_errorinit_MASK 0x7fffffff /* bit 31 */ - #define S_errorinit_disable 0x0 - #define S_errorinit_enable 0x80000000 - - #define FSC_x_off_MASK 0xfffffff0 /* bits 0-3 */ - #define FSC_x_off_SHIFT 0 - #define FSC_funcnt_MASK 0xffffff80 /* bits 0-6 */ - #define FSC_funcnt_SHIFT 0 - #define FSC_y_off_MASK 0xffffff8f /* bits 4-6 */ - #define FSC_y_off_SHIFT 4 - #define FSC_funoff_MASK 0xffc0ffff /* bits 16-21 */ - #define FSC_funoff_SHIFT 16 - #define FSC_stylelen_MASK 0xffc0ffff /* bits 16-21 */ - #define FSC_stylelen_SHIFT 16 - - - #define STH_softraphand_MASK 0x3 /* bits 2-31 */ - #define STH_softraphand_SHIFT 2 - - #define SO_srcmap_MASK 0xfffffffe /* bit 0 */ - #define SO_srcmap_fb 0x0 - #define SO_srcmap_sys 0x1 - #define SO_srcacc_MASK 0xfffffffd /* bit 1 */ - #define SO_srcacc_pci 0x0 - #define SO_srcacc_agp 0x2 - #define SO_srcorg_MASK 0x7 /* bits 3-31 */ - #define SO_srcorg_SHIFT 3 - - #define STAT_softrapen_MASK 0xfffffffe /* bit 0 */ - #define STAT_softrapen_disable 0x0 - #define STAT_softrapen_enable 0x1 - #define STAT_pickpen_MASK 0xfffffffb /* bit 2 */ - #define STAT_pickpen_disable 0x0 - #define STAT_pickpen_enable 0x4 - #define STAT_vsyncsts_MASK 0xfffffff7 /* bit 3 */ - #define STAT_vsyncsts_disable 0x0 - #define STAT_vsyncsts_enable 0x8 - #define STAT_vsyncpen_MASK 0xffffffef /* bit 4 */ - #define STAT_vsyncpen_disable 0x0 - #define STAT_vsyncpen_enable 0x10 - #define STAT_vlinepen_MASK 0xffffffdf /* bit 5 */ - #define STAT_vlinepen_disable 0x0 - #define STAT_vlinepen_enable 0x20 - #define STAT_extpen_MASK 0xffffffbf /* bit 6 */ - #define STAT_extpen_disable 0x0 - #define STAT_extpen_enable 0x40 - #define STAT_wpen_MASK 0xffffff7f /* bit 7 */ - #define STAT_wpen_disable 0x0 - #define STAT_wpen_enable 0x80 - #define STAT_wcpen_MASK 0xfffffeff /* bit 8 */ - #define STAT_wcpen_disable 0x0 - #define STAT_wcpen_enable 0x100 - #define STAT_dwgengsts_MASK 0xfffeffff /* bit 16 */ - #define STAT_dwgengsts_disable 0x0 - #define STAT_dwgengsts_enable 0x10000 - #define STAT_endprdmasts_MASK 0xfffdffff /* bit 17 */ - #define STAT_endprdmasts_disable 0x0 - #define STAT_endprdmasts_enable 0x20000 - #define STAT_wbusy_MASK 0xfffbffff /* bit 18 */ - #define STAT_wbusy_disable 0x0 - #define STAT_wbusy_enable 0x40000 - #define STAT_swflag_MASK 0xfffffff /* bits 28-31 */ - #define STAT_swflag_SHIFT 28 - - #define S_sref_MASK 0xffffff00 /* bits 0-7 */ - #define S_sref_SHIFT 0 - #define S_smsk_MASK 0xffff00ff /* bits 8-15 */ - #define S_smsk_SHIFT 8 - #define S_swtmsk_MASK 0xff00ffff /* bits 16-23 */ - #define S_swtmsk_SHIFT 16 - - #define SC_smode_MASK 0xfffffff8 /* bits 0-2 */ - #define SC_smode_salways 0x0 /* val 0, shift 0 */ - #define SC_smode_snever 0x1 /* val 1, shift 0 */ - #define SC_smode_se 0x2 /* val 2, shift 0 */ - #define SC_smode_sne 0x3 /* val 3, shift 0 */ - #define SC_smode_slt 0x4 /* val 4, shift 0 */ - #define SC_smode_slte 0x5 /* val 5, shift 0 */ - #define SC_smode_sgt 0x6 /* val 6, shift 0 */ - #define SC_smode_sgte 0x7 /* val 7, shift 0 */ - #define SC_sfailop_MASK 0xffffffc7 /* bits 3-5 */ - #define SC_sfailop_keep 0x0 /* val 0, shift 3 */ - #define SC_sfailop_zero 0x8 /* val 1, shift 3 */ - #define SC_sfailop_replace 0x10 /* val 2, shift 3 */ - #define SC_sfailop_incrsat 0x18 /* val 3, shift 3 */ - #define SC_sfailop_decrsat 0x20 /* val 4, shift 3 */ - #define SC_sfailop_invert 0x28 /* val 5, shift 3 */ - #define SC_sfailop_incr 0x30 /* val 6, shift 3 */ - #define SC_sfailop_decr 0x38 /* val 7, shift 3 */ - #define SC_szfailop_MASK 0xfffffe3f /* bits 6-8 */ - #define SC_szfailop_keep 0x0 /* val 0, shift 6 */ - #define SC_szfailop_zero 0x40 /* val 1, shift 6 */ - #define SC_szfailop_replace 0x80 /* val 2, shift 6 */ - #define SC_szfailop_incrsat 0xc0 /* val 3, shift 6 */ - #define SC_szfailop_decrsat 0x100 /* val 4, shift 6 */ - #define SC_szfailop_invert 0x140 /* val 5, shift 6 */ - #define SC_szfailop_incr 0x180 /* val 6, shift 6 */ - #define SC_szfailop_decr 0x1c0 /* val 7, shift 6 */ - #define SC_szpassop_MASK 0xfffff1ff /* bits 9-11 */ - #define SC_szpassop_keep 0x0 /* val 0, shift 9 */ - #define SC_szpassop_zero 0x200 /* val 1, shift 9 */ - #define SC_szpassop_replace 0x400 /* val 2, shift 9 */ - #define SC_szpassop_incrsat 0x600 /* val 3, shift 9 */ - #define SC_szpassop_decrsat 0x800 /* val 4, shift 9 */ - #define SC_szpassop_invert 0xa00 /* val 5, shift 9 */ - #define SC_szpassop_incr 0xc00 /* val 6, shift 9 */ - #define SC_szpassop_decr 0xe00 /* val 7, shift 9 */ - - #define TD1_color1arg2selMASK 0xfffffffc /* bits 0-1 */ - #define TD1_color1alphaselMASK 0xffffffe3 /* bits 2-4 */ - #define TD1_color1alphaselSHIFT 2 - #define TD1_color1arg1alphaMASK 0xffffffdf /* bit 5 */ - #define TD1_color1arg1alphadisable 0x0 - #define TD1_color1arg1alphaenable 0x20 - #define TD1_color1arg1invMASK 0xffffffbf /* bit 6 */ - #define TD1_color1arg1invdisable 0x0 - #define TD1_color1arg1invenable 0x40 - #define TD1_color1arg2alphaMASK 0xffffff7f /* bit 7 */ - #define TD1_color1arg2alphadisable 0x0 - #define TD1_color1arg2alphaenable 0x80 - #define TD1_color1arg2invMASK 0xfffffeff /* bit 8 */ - #define TD1_color1arg2invdisable 0x0 - #define TD1_color1arg2invenable 0x100 - #define TD1_color1alpha1invMASK 0xfffffdff /* bit 9 */ - #define TD1_color1alpha1invdisable 0x0 - #define TD1_color1alpha1invenable 0x200 - #define TD1_color1alpha2invMASK 0xfffffbff /* bit 10 */ - #define TD1_color1alpha2invdisable 0x0 - #define TD1_color1alpha2invenable 0x400 - #define TD1_color1selMASK 0xff9fffff /* bits 21-22 */ - #define TD1_color1selarg1 0x0 /* val 0, shift 21 */ - #define TD1_color1selarg2 0x200000 /* val 1, shift 21 */ - #define TD1_color1seladd 0x400000 /* val 2, shift 21 */ - #define TD1_color1selmul 0x600000 /* val 3, shift 21 */ - #define TD1_alpha1selMASK 0x3fffffff /* bits 30-31 */ - #define TD1_alpha1selarg1 0x0 /* val 0, shift 30 */ - #define TD1_alpha1selarg2 0x40000000 /* val 1, shift 30 */ - #define TD1_alpha1seladd 0x80000000 /* val 2, shift 30 */ - #define TD1_alpha1selmul 0xc0000000 /* val 3, shift 30 */ - - #define TST_ramtsten_MASK 0xfffffffe /* bit 0 */ - #define TST_ramtsten_disable 0x0 - #define TST_ramtsten_enable 0x1 - #define TST_ramtstdone_MASK 0xfffffffd /* bit 1 */ - #define TST_ramtstdone_disable 0x0 - #define TST_ramtstdone_enable 0x2 - #define TST_wramtstpass_MASK 0xfffffffb /* bit 2 */ - #define TST_wramtstpass_disable 0x0 - #define TST_wramtstpass_enable 0x4 - #define TST_tcachetstpass_MASK 0xfffffff7 /* bit 3 */ - #define TST_tcachetstpass_disable 0x0 - #define TST_tcachetstpass_enable 0x8 - #define TST_tluttstpass_MASK 0xffffffef /* bit 4 */ - #define TST_tluttstpass_disable 0x0 - #define TST_tluttstpass_enable 0x10 - #define TST_luttstpass_MASK 0xffffffdf /* bit 5 */ - #define TST_luttstpass_disable 0x0 - #define TST_luttstpass_enable 0x20 - #define TST_besramtstpass_MASK 0xffffffbf /* bit 6 */ - #define TST_besramtstpass_disable 0x0 - #define TST_besramtstpass_enable 0x40 - #define TST_ringen_MASK 0xfffffeff /* bit 8 */ - #define TST_ringen_disable 0x0 - #define TST_ringen_enable 0x100 - #define TST_apllbyp_MASK 0xfffffdff /* bit 9 */ - #define TST_apllbyp_disable 0x0 - #define TST_apllbyp_enable 0x200 - #define TST_hiten_MASK 0xfffffbff /* bit 10 */ - #define TST_hiten_disable 0x0 - #define TST_hiten_enable 0x400 - #define TST_tmode_MASK 0xffffc7ff /* bits 11-13 */ - #define TST_tmode_SHIFT 11 - #define TST_tclksel_MASK 0xfffe3fff /* bits 14-16 */ - #define TST_tclksel_SHIFT 14 - #define TST_ringcnten_MASK 0xfffdffff /* bit 17 */ - #define TST_ringcnten_disable 0x0 - #define TST_ringcnten_enable 0x20000 - #define TST_ringcnt_MASK 0xc003ffff /* bits 18-29 */ - #define TST_ringcnt_SHIFT 18 - #define TST_ringcntclksl_MASK 0xbfffffff /* bit 30 */ - #define TST_ringcntclksl_disable 0x0 - #define TST_ringcntclksl_enable 0x40000000 - #define TST_biosboot_MASK 0x7fffffff /* bit 31 */ - #define TST_biosboot_disable 0x0 - #define TST_biosboot_enable 0x80000000 - - #define TMC_tformat_MASK 0xfffffff0 /* bits 0-3 */ - #define TMC_tformat_tw4 0x0 /* val 0, shift 0 */ - #define TMC_tformat_tw8 0x1 /* val 1, shift 0 */ - #define TMC_tformat_tw15 0x2 /* val 2, shift 0 */ - #define TMC_tformat_tw16 0x3 /* val 3, shift 0 */ - #define TMC_tformat_tw12 0x4 /* val 4, shift 0 */ - #define TMC_tformat_tw32 0x6 /* val 6, shift 0 */ - #define TMC_tformat_tw422 0xa /* val 10, shift 0 */ - #define TMC_tpitchlin_MASK 0xfffffeff /* bit 8 */ - #define TMC_tpitchlin_disable 0x0 - #define TMC_tpitchlin_enable 0x100 - #define TMC_tpitchext_MASK 0xfff001ff /* bits 9-19 */ - #define TMC_tpitchext_SHIFT 9 - #define TMC_tpitch_MASK 0xfff8ffff /* bits 16-18 */ - #define TMC_tpitch_SHIFT 16 - #define TMC_owalpha_MASK 0xffbfffff /* bit 22 */ - #define TMC_owalpha_disable 0x0 - #define TMC_owalpha_enable 0x400000 - #define TMC_azeroextend_MASK 0xff7fffff /* bit 23 */ - #define TMC_azeroextend_disable 0x0 - #define TMC_azeroextend_enable 0x800000 - #define TMC_decalckey_MASK 0xfeffffff /* bit 24 */ - #define TMC_decalckey_disable 0x0 - #define TMC_decalckey_enable 0x1000000 - #define TMC_takey_MASK 0xfdffffff /* bit 25 */ - #define TMC_takey_0 0x0 - #define TMC_takey_1 0x2000000 - #define TMC_tamask_MASK 0xfbffffff /* bit 26 */ - #define TMC_tamask_0 0x0 - #define TMC_tamask_1 0x4000000 - #define TMC_clampv_MASK 0xf7ffffff /* bit 27 */ - #define TMC_clampv_disable 0x0 - #define TMC_clampv_enable 0x8000000 - #define TMC_clampu_MASK 0xefffffff /* bit 28 */ - #define TMC_clampu_disable 0x0 - #define TMC_clampu_enable 0x10000000 - #define TMC_tmodulate_MASK 0xdfffffff /* bit 29 */ - #define TMC_tmodulate_disable 0x0 - #define TMC_tmodulate_enable 0x20000000 - #define TMC_strans_MASK 0xbfffffff /* bit 30 */ - #define TMC_strans_disable 0x0 - #define TMC_strans_enable 0x40000000 - #define TMC_itrans_MASK 0x7fffffff /* bit 31 */ - #define TMC_itrans_disable 0x0 - #define TMC_itrans_enable 0x80000000 - - #define TMC_decalblend_MASK 0xfffffffe /* bit 0 */ - #define TMC_decalblend_disable 0x0 - #define TMC_decalblend_enable 0x1 - #define TMC_idecal_MASK 0xfffffffd /* bit 1 */ - #define TMC_idecal_disable 0x0 - #define TMC_idecal_enable 0x2 - #define TMC_decaldis_MASK 0xfffffffb /* bit 2 */ - #define TMC_decaldis_disable 0x0 - #define TMC_decaldis_enable 0x4 - #define TMC_ckstransdis_MASK 0xffffffef /* bit 4 */ - #define TMC_ckstransdis_disable 0x0 - #define TMC_ckstransdis_enable 0x10 - #define TMC_borderen_MASK 0xffffffdf /* bit 5 */ - #define TMC_borderen_disable 0x0 - #define TMC_borderen_enable 0x20 - #define TMC_specen_MASK 0xffffffbf /* bit 6 */ - #define TMC_specen_disable 0x0 - #define TMC_specen_enable 0x40 - - #define TF_minfilter_MASK 0xfffffff0 /* bits 0-3 */ - #define TF_minfilter_nrst 0x0 /* val 0, shift 0 */ - #define TF_minfilter_bilin 0x2 /* val 2, shift 0 */ - #define TF_minfilter_cnst 0x3 /* val 3, shift 0 */ - #define TF_minfilter_mm1s 0x8 /* val 8, shift 0 */ - #define TF_minfilter_mm2s 0x9 /* val 9, shift 0 */ - #define TF_minfilter_mm4s 0xa /* val 10, shift 0 */ - #define TF_minfilter_mm8s 0xc /* val 12, shift 0 */ - #define TF_magfilter_MASK 0xffffff0f /* bits 4-7 */ - #define TF_magfilter_nrst 0x0 /* val 0, shift 4 */ - #define TF_magfilter_bilin 0x20 /* val 2, shift 4 */ - #define TF_magfilter_cnst 0x30 /* val 3, shift 4 */ - #define TF_avgstride_MASK 0xfff7ffff /* bit 19 */ - #define TF_avgstride_disable 0x0 - #define TF_avgstride_enable 0x80000 - #define TF_filteralpha_MASK 0xffefffff /* bit 20 */ - #define TF_filteralpha_disable 0x0 - #define TF_filteralpha_enable 0x100000 - #define TF_fthres_MASK 0xe01fffff /* bits 21-28 */ - #define TF_fthres_SHIFT 21 - #define TF_mapnb_MASK 0x1fffffff /* bits 29-31 */ - #define TF_mapnb_SHIFT 29 - - #define TH_th_MASK 0xffffffc0 /* bits 0-5 */ - #define TH_th_SHIFT 0 - #define TH_rfh_MASK 0xffff81ff /* bits 9-14 */ - #define TH_rfh_SHIFT 9 - #define TH_thmask_MASK 0xe003ffff /* bits 18-28 */ - #define TH_thmask_SHIFT 18 - - #define TO_texorgmap_MASK 0xfffffffe /* bit 0 */ - #define TO_texorgmap_fb 0x0 - #define TO_texorgmap_sys 0x1 - #define TO_texorgacc_MASK 0xfffffffd /* bit 1 */ - #define TO_texorgacc_pci 0x0 - #define TO_texorgacc_agp 0x2 - #define TO_texorg_MASK 0x1f /* bits 5-31 */ - #define TO_texorg_SHIFT 5 - - #define TT_tckey_MASK 0xffff0000 /* bits 0-15 */ - #define TT_tckey_SHIFT 0 - #define TT_tkmask_MASK 0xffff /* bits 16-31 */ - #define TT_tkmask_SHIFT 16 - - #define TT_tckeyh_MASK 0xffff0000 /* bits 0-15 */ - #define TT_tckeyh_SHIFT 0 - #define TT_tkmaskh_MASK 0xffff /* bits 16-31 */ - #define TT_tkmaskh_SHIFT 16 - - #define TW_tw_MASK 0xffffffc0 /* bits 0-5 */ - #define TW_tw_SHIFT 0 - #define TW_rfw_MASK 0xffff81ff /* bits 9-14 */ - #define TW_rfw_SHIFT 9 - #define TW_twmask_MASK 0xe003ffff /* bits 18-28 */ - #define TW_twmask_SHIFT 18 - - #define WAS_seqdst0_MASK 0xffffffc0 /* bits 0-5 */ - #define WAS_seqdst0_SHIFT 0 - #define WAS_seqdst1_MASK 0xfffff03f /* bits 6-11 */ - #define WAS_seqdst1_SHIFT 6 - #define WAS_seqdst2_MASK 0xfffc0fff /* bits 12-17 */ - #define WAS_seqdst2_SHIFT 12 - #define WAS_seqdst3_MASK 0xff03ffff /* bits 18-23 */ - #define WAS_seqdst3_SHIFT 18 - #define WAS_seqlen_MASK 0xfcffffff /* bits 24-25 */ - #define WAS_wfirsttag_MASK 0xfbffffff /* bit 26 */ - #define WAS_wfirsttag_disable 0x0 - #define WAS_wfirsttag_enable 0x4000000 - #define WAS_wsametag_MASK 0xf7ffffff /* bit 27 */ - #define WAS_wsametag_disable 0x0 - #define WAS_wsametag_enable 0x8000000 - #define WAS_seqoff_MASK 0xefffffff /* bit 28 */ - #define WAS_seqoff_disable 0x0 - #define WAS_seqoff_enable 0x10000000 - - #define WMA_wcodeaddr_MASK 0xff /* bits 8-31 */ - #define WMA_wcodeaddr_SHIFT 8 - - #define WF_walustsflag_MASK 0xffffff00 /* bits 0-7 */ - #define WF_walustsflag_SHIFT 0 - #define WF_walucfgflag_MASK 0xffff00ff /* bits 8-15 */ - #define WF_walucfgflag_SHIFT 8 - #define WF_wprgflag_MASK 0xffff /* bits 16-31 */ - #define WF_wprgflag_SHIFT 16 - - #define WF1_walustsflag1_MASK 0xffffff00 /* bits 0-7 */ - #define WF1_walustsflag1_SHIFT 0 - #define WF1_walucfgflag1_MASK 0xffff00ff /* bits 8-15 */ - #define WF1_walucfgflag1_SHIFT 8 - #define WF1_wprgflag1_MASK 0xffff /* bits 16-31 */ - #define WF1_wprgflag1_SHIFT 16 - - #define WGV_wgetmsbmin_MASK 0xffffffe0 /* bits 0-4 */ - #define WGV_wgetmsbmin_SHIFT 0 - #define WGV_wgetmsbmax_MASK 0xffffe0ff /* bits 8-12 */ - #define WGV_wgetmsbmax_SHIFT 8 - #define WGV_wbrklefttop_MASK 0xfffeffff /* bit 16 */ - #define WGV_wbrklefttop_disable 0x0 - #define WGV_wbrklefttop_enable 0x10000 - #define WGV_wfastcrop_MASK 0xfffdffff /* bit 17 */ - #define WGV_wfastcrop_disable 0x0 - #define WGV_wfastcrop_enable 0x20000 - #define WGV_wcentersnap_MASK 0xfffbffff /* bit 18 */ - #define WGV_wcentersnap_disable 0x0 - #define WGV_wcentersnap_enable 0x40000 - #define WGV_wbrkrighttop_MASK 0xfff7ffff /* bit 19 */ - #define WGV_wbrkrighttop_disable 0x0 - #define WGV_wbrkrighttop_enable 0x80000 - - #define WIA_wmode_MASK 0xfffffffc /* bits 0-1 */ - #define WIA_wmode_suspend 0x0 /* val 0, shift 0 */ - #define WIA_wmode_resume 0x1 /* val 1, shift 0 */ - #define WIA_wmode_jump 0x2 /* val 2, shift 0 */ - #define WIA_wmode_start 0x3 /* val 3, shift 0 */ - #define WIA_wagp_MASK 0xfffffffb /* bit 2 */ - #define WIA_wagp_pci 0x0 - #define WIA_wagp_agp 0x4 - #define WIA_wiaddr_MASK 0x7 /* bits 3-31 */ - #define WIA_wiaddr_SHIFT 3 - - #define WIA2_wmode_MASK 0xfffffffc /* bits 0-1 */ - #define WIA2_wmode_suspend 0x0 /* val 0, shift 0 */ - #define WIA2_wmode_resume 0x1 /* val 1, shift 0 */ - #define WIA2_wmode_jump 0x2 /* val 2, shift 0 */ - #define WIA2_wmode_start 0x3 /* val 3, shift 0 */ - #define WIA2_wagp_MASK 0xfffffffb /* bit 2 */ - #define WIA2_wagp_pci 0x0 - #define WIA2_wagp_agp 0x4 - #define WIA2_wiaddr_MASK 0x7 /* bits 3-31 */ - #define WIA2_wiaddr_SHIFT 3 - - #define WIMA_wimemaddr_MASK 0xffffff00 /* bits 0-7 */ - #define WIMA_wimemaddr_SHIFT 0 - - #define WM_wucodecache_MASK 0xfffffffe /* bit 0 */ - #define WM_wucodecache_disable 0x0 - #define WM_wucodecache_enable 0x1 - #define WM_wmaster_MASK 0xfffffffd /* bit 1 */ - #define WM_wmaster_disable 0x0 - #define WM_wmaster_enable 0x2 - #define WM_wcacheflush_MASK 0xfffffff7 /* bit 3 */ - #define WM_wcacheflush_disable 0x0 - #define WM_wcacheflush_enable 0x8 - - #define WVS_wvrtxsz_MASK 0xffffffc0 /* bits 0-5 */ - #define WVS_wvrtxsz_SHIFT 0 - #define WVS_primsz_MASK 0xffffc0ff /* bits 8-13 */ - #define WVS_primsz_SHIFT 8 - - #define XYEA_x_end_MASK 0xffff0000 /* bits 0-15 */ - #define XYEA_x_end_SHIFT 0 - #define XYEA_y_end_MASK 0xffff /* bits 16-31 */ - #define XYEA_y_end_SHIFT 16 - - #define XYSA_x_start_MASK 0xffff0000 /* bits 0-15 */ - #define XYSA_x_start_SHIFT 0 - #define XYSA_y_start_MASK 0xffff /* bits 16-31 */ - #define XYSA_y_start_SHIFT 16 - - #define YA_ydst_MASK 0xff800000 /* bits 0-22 */ - #define YA_ydst_SHIFT 0 - #define YA_sellin_MASK 0x1fffffff /* bits 29-31 */ - #define YA_sellin_SHIFT 29 - - #define YDL_length_MASK 0xffff0000 /* bits 0-15 */ - #define YDL_length_SHIFT 0 - #define YDL_yval_MASK 0xffff /* bits 16-31 */ - #define YDL_yval_SHIFT 16 - - #define ZO_zorgmap_MASK 0xfffffffe /* bit 0 */ - #define ZO_zorgmap_fb 0x0 - #define ZO_zorgmap_sys 0x1 - #define ZO_zorgacc_MASK 0xfffffffd /* bit 1 */ - #define ZO_zorgacc_pci 0x0 - #define ZO_zorgacc_agp 0x2 - #define ZO_zorg_MASK 0x3 /* bits 2-31 */ - #define ZO_zorg_SHIFT 2 - - - - -/**************** (END) AUTOMATICLY GENERATED REGISTER FILE ******************/ - -#endif /* _MGAREGS_H_ */ - diff --git a/linux/picker.c b/linux/picker.c index ecdb2c15a..0bd8bfd57 100644 --- a/linux/picker.c +++ b/linux/picker.c @@ -9,6 +9,16 @@ #define CONFIG_MODVERSIONS 0 #endif +#ifndef CONFIG_AGP_MODULE +#define CONFIG_AGP_MODULE 0 +#endif + +#ifndef CONFIG_AGP +#define CONFIG_AGP 0 +#endif + SMP = CONFIG_SMP MODVERSIONS = CONFIG_MODVERSIONS +AGP = CONFIG_AGP +AGP_MODULE = CONFIG_AGP_MODULE RELEASE = UTS_RELEASE diff --git a/linux/proc.c b/linux/proc.c index 54aba58c4..db98fd6a4 100644 --- a/linux/proc.c +++ b/linux/proc.c @@ -164,7 +164,10 @@ static int _drm_vm_info(char *buf, char **start, off_t offset, int len, { drm_device_t *dev = (drm_device_t *)data; drm_map_t *map; - const char *types[] = { "FB", "REG", "SHM" }; + /* Hardcoded from _DRM_FRAME_BUFFER, + _DRM_REGISTERS, _DRM_SHM, and + _DRM_AGP. */ + const char *types[] = { "FB", "REG", "SHM", "AGP" }; const char *type; int i; @@ -175,7 +178,7 @@ static int _drm_vm_info(char *buf, char **start, off_t offset, int len, "address mtrr\n\n"); for (i = 0; i < dev->map_count; i++) { map = dev->maplist[i]; - if (map->type < 0 || map->type > 2) type = "??"; + if (map->type < 0 || map->type > 3) type = "??"; else type = types[map->type]; DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s 0x%02x 0x%08lx ", i, diff --git a/linux/tdfx_context.c b/linux/tdfx_context.c index 842d6f5d5..74b107bd2 100644 --- a/linux/tdfx_context.c +++ b/linux/tdfx_context.c @@ -38,9 +38,7 @@ extern drm_ctx_t tdfx_res_ctx; static int tdfx_alloc_queue(drm_device_t *dev) { - static int context = 0; - - return ++context; /* Should this reuse contexts in the future? */ + return drm_ctxbitmap_next(dev); } int tdfx_context_switch(drm_device_t *dev, int old, int new) @@ -137,6 +135,12 @@ int tdfx_addctx(struct inode *inode, struct file *filp, unsigned int cmd, ctx.handle = tdfx_alloc_queue(dev); } DRM_DEBUG("%d\n", ctx.handle); + if (ctx.handle == -1) { + DRM_DEBUG("Not enough free contexts.\n"); + /* Should this return -EBUSY instead? */ + return -ENOMEM; + } + copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT); return 0; } @@ -193,13 +197,13 @@ int tdfx_newctx(struct inode *inode, struct file *filp, unsigned int cmd, int tdfx_rmctx(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_ctx_t ctx; copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); DRM_DEBUG("%d\n", ctx.handle); - /* This is currently a noop because we - don't reuse context values. Perhaps we - should? */ - + drm_ctxbitmap_free(dev, ctx.handle); + return 0; } diff --git a/linux/tdfx_drv.c b/linux/tdfx_drv.c index 57c1c719d..fb7a997b4 100644 --- a/linux/tdfx_drv.c +++ b/linux/tdfx_drv.c @@ -85,6 +85,16 @@ static drm_ioctl_desc_t tdfx_ioctls[] = { [DRM_IOCTL_NR(DRM_IOCTL_LOCK)] = { tdfx_lock, 1, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = { tdfx_unlock, 1, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { drm_finish, 1, 0 }, +#ifdef DRM_AGP + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)] = {drm_agp_acquire, 1, 1}, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)] = {drm_agp_release, 1, 1}, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)] = {drm_agp_enable, 1, 1}, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)] = {drm_agp_info, 1, 1}, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)] = {drm_agp_alloc, 1, 1}, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)] = {drm_agp_free, 1, 1}, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = {drm_agp_unbind, 1, 1}, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = {drm_agp_bind, 1, 1}, +#endif }; #define TDFX_IOCTL_COUNT DRM_ARRAY_SIZE(tdfx_ioctls) @@ -228,7 +238,24 @@ static int tdfx_takedown(drm_device_t *dev) } dev->magiclist[i].head = dev->magiclist[i].tail = NULL; } - +#ifdef DRM_AGP + /* Clear AGP information */ + if (dev->agp) { + drm_agp_mem_t *temp; + drm_agp_mem_t *temp_next; + + temp = dev->agp->memory; + while(temp != NULL) { + temp_next = temp->next; + drm_free_agp(temp->memory, temp->pages); + drm_free(temp, sizeof(*temp), DRM_MEM_AGPLISTS); + temp = temp_next; + } + if(dev->agp->acquired) (*drm_agp.release)(); + drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS); + dev->agp = NULL; + } +#endif /* Clear vma list (only built for debugging) */ if (dev->vmalist) { for (vma = dev->vmalist; vma; vma = vma_next) { @@ -262,6 +289,10 @@ static int tdfx_takedown(drm_device_t *dev) - PAGE_SHIFT, DRM_MEM_SAREA); break; + case _DRM_AGP: + /* Do nothing here, because this is all + handled in the AGP/GART driver. */ + break; } drm_free(map, sizeof(*map), DRM_MEM_MAPS); } @@ -309,6 +340,16 @@ int tdfx_init(void) drm_mem_init(); drm_proc_init(dev); +#ifdef DRM_AGP + dev->agp = drm_agp_init(); +#endif + if((retcode = drm_ctxbitmap_init(dev))) { + DRM_ERROR("Cannot allocate memory for context bitmap.\n"); + drm_proc_cleanup(); + misc_deregister(&tdfx_misc); + tdfx_takedown(dev); + return retcode; + } DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", TDFX_NAME, @@ -335,6 +376,7 @@ void tdfx_cleanup(void) } else { DRM_INFO("Module unloaded\n"); } + drm_ctxbitmap_cleanup(dev); tdfx_takedown(dev); } diff --git a/linux/vm.c b/linux/vm.c index 85470ac52..389f2faee 100644 --- a/linux/vm.c +++ b/linux/vm.c @@ -250,9 +250,10 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) switch (map->type) { case _DRM_FRAME_BUFFER: case _DRM_REGISTERS: + case _DRM_AGP: if (VM_OFFSET(vma) >= __pa(high_memory)) { #if defined(__i386__) - if (boot_cpu_data.x86 > 3) { + if (boot_cpu_data.x86 > 3 && map->type != _DRM_AGP) { pgprot_val(vma->vm_page_prot) |= _PAGE_PCD; pgprot_val(vma->vm_page_prot) &= ~_PAGE_PWT; } diff --git a/shared-core/drm.h b/shared-core/drm.h index 7b8e88265..ae4c65ca3 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -61,6 +61,19 @@ typedef unsigned int drm_context_t; typedef unsigned int drm_drawable_t; typedef unsigned int drm_magic_t; +/* Warning: If you change this structure, make sure you change + * XF86DRIClipRectRec in the server as well */ + +typedef struct drm_clip_rect { + unsigned short x1; + unsigned short y1; + unsigned short x2; + unsigned short y2; +} drm_clip_rect_t; + +/* Seperate include files for the i810/mga specific structures */ +#include "mga_drm.h" +#include "i810_drm.h" typedef struct drm_version { int version_major; /* Major version */ @@ -101,7 +114,8 @@ typedef struct drm_control { typedef enum drm_map_type { _DRM_FRAME_BUFFER = 0, /* WC (no caching), no core dump */ _DRM_REGISTERS = 1, /* no caching, no core dump */ - _DRM_SHM = 2 /* shared, cached */ + _DRM_SHM = 2, /* shared, cached */ + _DRM_AGP = 3 /* AGP/GART */ } drm_map_type_t; typedef enum drm_map_flags { @@ -165,8 +179,11 @@ typedef struct drm_buf_desc { int low_mark; /* Low water mark */ int high_mark; /* High water mark */ enum { - DRM_PAGE_ALIGN = 0x01 /* Align on page boundaries for DMA */ + _DRM_PAGE_ALIGN = 0x01, /* Align on page boundaries for DMA */ + _DRM_AGP_BUFFER = 0x02 /* Buffer is in agp space */ } flags; + unsigned long agp_start; /* Start address of where the agp buffers + * are in the agp aperture */ } drm_buf_desc_t; typedef struct drm_buf_info { @@ -237,6 +254,38 @@ typedef struct drm_irq_busid { int funcnum; } drm_irq_busid_t; +typedef struct drm_agp_mode { + unsigned long mode; +} drm_agp_mode_t; + + /* For drm_agp_alloc -- allocated a buffer */ +typedef struct drm_agp_buffer { + unsigned long size; /* In bytes -- will round to page boundary */ + unsigned long handle; /* Used for BIND/UNBIND ioctls */ + unsigned long type; /* Type of memory to allocate */ + unsigned long physical; /* Physical used by i810 */ +} drm_agp_buffer_t; + + /* For drm_agp_bind */ +typedef struct drm_agp_binding { + unsigned long handle; /* From drm_agp_buffer */ + unsigned long offset; /* In bytes -- will round to page boundary */ +} drm_agp_binding_t; + +typedef struct drm_agp_info { + int agp_version_major; + int agp_version_minor; + unsigned long mode; + unsigned long aperture_base; /* physical address */ + unsigned long aperture_size; /* bytes */ + unsigned long memory_allowed; /* bytes */ + unsigned long memory_used; + + /* PCI information */ + unsigned short id_vendor; + unsigned short id_device; +} drm_agp_info_t; + #define DRM_IOCTL_BASE 'd' #define DRM_IOCTL_NR(n) _IOC_NR(n) #define DRM_IO(nr) _IO(DRM_IOCTL_BASE,nr) @@ -276,4 +325,28 @@ typedef struct drm_irq_busid { #define DRM_IOCTL_UNLOCK DRM_IOW( 0x2b, drm_lock_t) #define DRM_IOCTL_FINISH DRM_IOW( 0x2c, drm_lock_t) +#define DRM_IOCTL_AGP_ACQUIRE DRM_IO( 0x30) +#define DRM_IOCTL_AGP_RELEASE DRM_IO( 0x31) +#define DRM_IOCTL_AGP_ENABLE DRM_IOR( 0x32, drm_agp_mode_t) +#define DRM_IOCTL_AGP_INFO DRM_IOW( 0x33, drm_agp_info_t) +#define DRM_IOCTL_AGP_ALLOC DRM_IOWR(0x34, drm_agp_buffer_t) +#define DRM_IOCTL_AGP_FREE DRM_IOW( 0x35, drm_agp_buffer_t) +#define DRM_IOCTL_AGP_BIND DRM_IOWR(0x36, drm_agp_binding_t) +#define DRM_IOCTL_AGP_UNBIND DRM_IOW( 0x37, drm_agp_binding_t) + +/* Mga specific ioctls */ +#define DRM_IOCTL_MGA_INIT DRM_IOW( 0x40, drm_mga_init_t) +#define DRM_IOCTL_MGA_SWAP DRM_IOW( 0x41, drm_mga_swap_t) +#define DRM_IOCTL_MGA_CLEAR DRM_IOW( 0x42, drm_mga_clear_t) +#define DRM_IOCTL_MGA_ILOAD DRM_IOW( 0x43, drm_mga_iload_t) +#define DRM_IOCTL_MGA_VERTEX DRM_IOW( 0x44, drm_mga_vertex_t) +#define DRM_IOCTL_MGA_FLUSH DRM_IOW( 0x45, drm_lock_t ) + +/* I810 specific ioctls */ +#define DRM_IOCTL_I810_INIT DRM_IOW( 0x40, drm_i810_init_t) +#define DRM_IOCTL_I810_VERTEX DRM_IOW( 0x41, drm_i810_vertex_t) +#define DRM_IOCTL_I810_DMA DRM_IOW( 0x42, drm_i810_general_t) +#define DRM_IOCTL_I810_FLUSH DRM_IO ( 0x43) +#define DRM_IOCTL_I810_GETAGE DRM_IO ( 0x44) + #endif diff --git a/shared/drm.h b/shared/drm.h index 7b8e88265..ae4c65ca3 100644 --- a/shared/drm.h +++ b/shared/drm.h @@ -61,6 +61,19 @@ typedef unsigned int drm_context_t; typedef unsigned int drm_drawable_t; typedef unsigned int drm_magic_t; +/* Warning: If you change this structure, make sure you change + * XF86DRIClipRectRec in the server as well */ + +typedef struct drm_clip_rect { + unsigned short x1; + unsigned short y1; + unsigned short x2; + unsigned short y2; +} drm_clip_rect_t; + +/* Seperate include files for the i810/mga specific structures */ +#include "mga_drm.h" +#include "i810_drm.h" typedef struct drm_version { int version_major; /* Major version */ @@ -101,7 +114,8 @@ typedef struct drm_control { typedef enum drm_map_type { _DRM_FRAME_BUFFER = 0, /* WC (no caching), no core dump */ _DRM_REGISTERS = 1, /* no caching, no core dump */ - _DRM_SHM = 2 /* shared, cached */ + _DRM_SHM = 2, /* shared, cached */ + _DRM_AGP = 3 /* AGP/GART */ } drm_map_type_t; typedef enum drm_map_flags { @@ -165,8 +179,11 @@ typedef struct drm_buf_desc { int low_mark; /* Low water mark */ int high_mark; /* High water mark */ enum { - DRM_PAGE_ALIGN = 0x01 /* Align on page boundaries for DMA */ + _DRM_PAGE_ALIGN = 0x01, /* Align on page boundaries for DMA */ + _DRM_AGP_BUFFER = 0x02 /* Buffer is in agp space */ } flags; + unsigned long agp_start; /* Start address of where the agp buffers + * are in the agp aperture */ } drm_buf_desc_t; typedef struct drm_buf_info { @@ -237,6 +254,38 @@ typedef struct drm_irq_busid { int funcnum; } drm_irq_busid_t; +typedef struct drm_agp_mode { + unsigned long mode; +} drm_agp_mode_t; + + /* For drm_agp_alloc -- allocated a buffer */ +typedef struct drm_agp_buffer { + unsigned long size; /* In bytes -- will round to page boundary */ + unsigned long handle; /* Used for BIND/UNBIND ioctls */ + unsigned long type; /* Type of memory to allocate */ + unsigned long physical; /* Physical used by i810 */ +} drm_agp_buffer_t; + + /* For drm_agp_bind */ +typedef struct drm_agp_binding { + unsigned long handle; /* From drm_agp_buffer */ + unsigned long offset; /* In bytes -- will round to page boundary */ +} drm_agp_binding_t; + +typedef struct drm_agp_info { + int agp_version_major; + int agp_version_minor; + unsigned long mode; + unsigned long aperture_base; /* physical address */ + unsigned long aperture_size; /* bytes */ + unsigned long memory_allowed; /* bytes */ + unsigned long memory_used; + + /* PCI information */ + unsigned short id_vendor; + unsigned short id_device; +} drm_agp_info_t; + #define DRM_IOCTL_BASE 'd' #define DRM_IOCTL_NR(n) _IOC_NR(n) #define DRM_IO(nr) _IO(DRM_IOCTL_BASE,nr) @@ -276,4 +325,28 @@ typedef struct drm_irq_busid { #define DRM_IOCTL_UNLOCK DRM_IOW( 0x2b, drm_lock_t) #define DRM_IOCTL_FINISH DRM_IOW( 0x2c, drm_lock_t) +#define DRM_IOCTL_AGP_ACQUIRE DRM_IO( 0x30) +#define DRM_IOCTL_AGP_RELEASE DRM_IO( 0x31) +#define DRM_IOCTL_AGP_ENABLE DRM_IOR( 0x32, drm_agp_mode_t) +#define DRM_IOCTL_AGP_INFO DRM_IOW( 0x33, drm_agp_info_t) +#define DRM_IOCTL_AGP_ALLOC DRM_IOWR(0x34, drm_agp_buffer_t) +#define DRM_IOCTL_AGP_FREE DRM_IOW( 0x35, drm_agp_buffer_t) +#define DRM_IOCTL_AGP_BIND DRM_IOWR(0x36, drm_agp_binding_t) +#define DRM_IOCTL_AGP_UNBIND DRM_IOW( 0x37, drm_agp_binding_t) + +/* Mga specific ioctls */ +#define DRM_IOCTL_MGA_INIT DRM_IOW( 0x40, drm_mga_init_t) +#define DRM_IOCTL_MGA_SWAP DRM_IOW( 0x41, drm_mga_swap_t) +#define DRM_IOCTL_MGA_CLEAR DRM_IOW( 0x42, drm_mga_clear_t) +#define DRM_IOCTL_MGA_ILOAD DRM_IOW( 0x43, drm_mga_iload_t) +#define DRM_IOCTL_MGA_VERTEX DRM_IOW( 0x44, drm_mga_vertex_t) +#define DRM_IOCTL_MGA_FLUSH DRM_IOW( 0x45, drm_lock_t ) + +/* I810 specific ioctls */ +#define DRM_IOCTL_I810_INIT DRM_IOW( 0x40, drm_i810_init_t) +#define DRM_IOCTL_I810_VERTEX DRM_IOW( 0x41, drm_i810_vertex_t) +#define DRM_IOCTL_I810_DMA DRM_IOW( 0x42, drm_i810_general_t) +#define DRM_IOCTL_I810_FLUSH DRM_IO ( 0x43) +#define DRM_IOCTL_I810_GETAGE DRM_IO ( 0x44) + #endif diff --git a/tests/drmstat.c b/tests/drmstat.c index 8fe6f7072..a96a38b26 100644 --- a/tests/drmstat.c +++ b/tests/drmstat.c @@ -187,7 +187,7 @@ int main(int argc, char **argv) case 'b': count = strtoul(optarg, &pt, 0); size = strtoul(pt+1, NULL, 0); - if ((r = drmAddBufs(fd, count, size, 0)) < 0) { + if ((r = drmAddBufs(fd, count, size, 0, 65536)) < 0) { drmError(r, argv[0]); return 1; } -- cgit v1.2.3