summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin E Martin <kem@kem.org>2000-03-21 03:15:04 +0000
committerKevin E Martin <kem@kem.org>2000-03-21 03:15:04 +0000
commitbaf435c4af839e35da43b6cb485fcb80fdf25d62 (patch)
tree1dff604c912ce8e3f7a90b0856a200a471ccec16
parent5bd8014f276d447178a1193d9dea1b976647d6ce (diff)
Updated r128 driver to XFree86 4.0 Included kernel code from mga branch
plus modifications for r128 Fixed compilation problem with DDC support and static X server
-rw-r--r--libdrm/xf86drm.c149
-rw-r--r--linux-core/Makefile.kernel20
-rw-r--r--linux-core/drmP.h127
-rw-r--r--linux-core/i810_dma.c1250
-rw-r--r--linux-core/i810_drv.c142
-rw-r--r--linux-core/i810_drv.h55
-rw-r--r--linux-core/mga_drv.c34
-rw-r--r--linux-core/r128_drv.c712
-rw-r--r--linux-core/tdfx_drv.c44
-rw-r--r--linux/Makefile.kernel20
-rw-r--r--linux/Makefile.linux54
-rw-r--r--linux/agpsupport.c19
-rw-r--r--linux/bufs.c7
-rw-r--r--linux/ctxbitmap.c4
-rw-r--r--linux/dma.c21
-rw-r--r--linux/drm.h50
-rw-r--r--linux/drmP.h127
-rw-r--r--linux/gamma_drv.c4
-rw-r--r--linux/i810_bufs.c338
-rw-r--r--linux/i810_context.c205
-rw-r--r--linux/i810_dma.c1250
-rw-r--r--linux/i810_dma.h118
-rw-r--r--linux/i810_drm_public.h139
-rw-r--r--linux/i810_drv.c142
-rw-r--r--linux/i810_drv.h55
-rw-r--r--linux/memory.c151
-rw-r--r--linux/mga_bufs.c23
-rw-r--r--linux/mga_context.c60
-rw-r--r--linux/mga_dma.c1513
-rw-r--r--linux/mga_dma.h146
-rw-r--r--linux/mga_drm_public.h146
-rw-r--r--linux/mga_drv.c34
-rw-r--r--linux/mga_drv.h70
-rw-r--r--linux/mga_state.c788
-rw-r--r--linux/mga_state.h3
-rw-r--r--linux/picker.c10
-rw-r--r--linux/proc.c7
-rw-r--r--linux/r128_context.c212
-rw-r--r--linux/r128_drv.c712
-rw-r--r--linux/r128_drv.h68
-rw-r--r--linux/tdfx_context.c18
-rw-r--r--linux/tdfx_drv.c44
-rw-r--r--linux/vm.c3
-rw-r--r--shared-core/drm.h50
-rw-r--r--shared/drm.h50
-rw-r--r--tests/drmstat.c2
46 files changed, 6801 insertions, 2395 deletions
diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c
index 3b0f98ac..ae81192b 100644
--- a/libdrm/xf86drm.c
+++ b/libdrm/xf86drm.c
@@ -1,8 +1,7 @@
/* xf86drm.c -- User-level interface to DRM device
* Created: Tue Jan 5 08:16:21 1999 by faith@precisioninsight.com
- * Revised: Sun Feb 13 23:43:32 2000 by kevin@precisioninsight.com
*
- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
@@ -24,6 +23,8 @@
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
+ * Author: Rickard E. (Rik) Faith <faith@precisioninsight.com>
+ *
* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/xf86drm.c,v 1.10 2000/02/23 04:47:23 martin Exp $
*
*/
@@ -143,7 +144,7 @@ static int drm_open(const char *file)
return -errno;
}
-/* drmAvailable looks for /proc/drm, and returns 1 if it is present. */
+/* drmAvailable looks for /proc/dri, and returns 1 if it is present. */
int drmAvailable(void)
{
@@ -418,7 +419,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 +429,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 +748,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 0;
+ 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 44d75c48..a169473a 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,12 @@ 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
+
+r128.o: r128_drv.o r128_context.o $(L_TARGET)
+ $(LD) $(LD_RFLAG) -r -o $@ r128_drv.o r128_context.o -L. -ldrm
diff --git a/linux-core/drmP.h b/linux-core/drmP.h
index 312fba36..c00d3bb0 100644
--- a/linux-core/drmP.h
+++ b/linux-core/drmP.h
@@ -48,8 +48,12 @@
#ifdef CONFIG_MTRR
#include <asm/mtrr.h>
#endif
+#ifdef DRM_AGP
+#include <linux/types.h>
+#include <linux/agp_backend.h>
+#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
#include <linux/poll.h>
#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 * 4 * 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 09959b65..e79f7ff5 100644
--- a/linux-core/i810_dma.c
+++ b/linux-core/i810_dma.c
@@ -24,7 +24,8 @@
* DEALINGS IN THE SOFTWARE.
*
* Authors: Rickard E. (Rik) Faith <faith@precisioninsight.com>
- * Jeff Hartmann <jhartmann@precisioninsight.com>
+ * Jeff Hartmann <jhartmann@precisioninsight.com>
+ * Keith Whitwell <keithw@precisioninsight.com>
*
* $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 $
*
@@ -32,9 +33,15 @@
#define __NO_VERSION__
#include "drmP.h"
+#include "i810_drm_public.h"
#include "i810_drv.h"
+#include "i810_dma.h"
#include <linux/interrupt.h> /* For task queue support */
+#include <linux/time.h> /* For do_gettimeofday */
+
+#define I810_BUF_FREE 1
+#define I810_BUF_USED 0
#define I810_REG(reg) 2
#define I810_BASE(reg) ((unsigned long) \
@@ -43,544 +50,460 @@
#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, 0); \
+ 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 __gettimeinmillis(void)
{
- 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_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;
- }
+ int millis;
+
+ millis = ((jiffies / HZ) * 1000) + ((jiffies % HZ) * (1000 / HZ));
+ return millis;
+}
- 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;
- }
+static int i810_wait_ring(drm_device_t *dev, int n, int timeout_millis)
+{
+ drm_i810_private_t *dev_priv = dev->dev_private;
+ drm_i810_ring_buffer_t *ring = &(dev_priv->ring);
+ int iters = 0;
+ int startTime = 0;
+ int curTime = 0;
+
+ if (timeout_millis == 0) timeout_millis = 3000;
+
+ while (ring->space < n) {
+ int i;
- 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);
+ 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++;
+ curTime = __gettimeinmillis();
+ if (startTime == 0 || curTime < startTime /*wrap case*/) {
+ startTime = curTime;
+ } else if (curTime - startTime > timeout_millis) {
+ DRM_ERROR("space: %d wanted %d\n", ring->space, n);
+ DRM_ERROR("lockup\n");
+ goto out_wait_ring;
}
- } 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;
- }
- }
-
- 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);
- }
-
- if ((retcode = drm_dma_enqueue(dev, d))) {
- if (d->flags & _DRM_DMA_BLOCK)
- remove_wait_queue(&last_buf->dma_wait, &entry);
- return retcode;
- }
+ 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;
- 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 inline void i810_dma_dispatch_general(drm_device_t *dev, drm_buf_t *buf)
{
- 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);
-
- 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;
- }
-
- 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;
- }
+ 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;
+ int length = buf->used;
+ 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( "length : 0x%x\n", length);
+ DRM_DEBUG( "start + length - 4 : 0x%lx\n", start + length - 4);
+ i810_kernel_lost_context(dev);
+
+ BEGIN_LP_RING(10);
+ OUT_RING( CMD_OP_BATCH_BUFFER );
+ OUT_RING( start | BB1_PROTECTED );
+ OUT_RING( start + length - 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.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");
+static inline void i810_dma_dispatch_vertex(drm_device_t *dev, drm_buf_t *buf)
+{
+ drm_i810_private_t *dev_priv = dev->dev_private;
+ drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+ drm_buf_t *real_buf = dev->dma->buflist[ buf_priv->vertex_real_idx ];
+ drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
+ xf86drmClipRectRec *box = sarea_priv->boxes;
+ int nbox = sarea_priv->nbox;
+ unsigned long address = (unsigned long)real_buf->bus_address;
+ unsigned long start = address - dev->agp->base;
+ int length = buf->used;
+ int i = 0;
+ RING_LOCALS;
- retcode = i810_dma_priority(dev, &d);
- }
+
+ if(nbox > I810_NR_SAREA_CLIPRECTS) nbox = I810_NR_SAREA_CLIPRECTS;
+
+ DRM_DEBUG("dispatch vertex addr 0x%lx, length 0x%x nbox %d\n",
+ address, length, buf_priv->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( "length : %d\n", length);
+ DRM_DEBUG( "start + length - 4 : %ld\n", start + length - 4);
+ i810_kernel_lost_context(dev);
+
+ if (!buf_priv->vertex_discard) {
+ 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 + length - 4 );
+ OUT_RING( 0 );
+ ADVANCE_LP_RING();
+
+ } while (++i < nbox);
+ }
+
+ BEGIN_LP_RING(8);
+ 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 );
+ OUT_RING( 0 );
+ ADVANCE_LP_RING();
+}
- d.granted_count = 0;
- if (!retcode && d.request_count) {
- retcode = drm_dma_get_buffers(dev, &d);
- }
+/* 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);
+}
- DRM_DEBUG("%d returning, granted = %d\n",
- current->pid, d.granted_count);
- copy_to_user_ret((drm_dma_t *)arg, &d, sizeof(d), -EFAULT);
+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;
- printk("i810_dma end (granted)\n");
- return retcode;
+ 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 +514,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 +527,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 +553,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 +572,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 +599,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 +618,143 @@ 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;
+ int startTime = 0;
+ int curTime = 0;
+ int timeout_millis = 3000;
+
+
+ if(dev_priv == NULL) {
+ return;
+ }
+ atomic_set(&dev_priv->flush_done, 0);
+ current->state = TASK_INTERRUPTIBLE;
+ add_wait_queue(&dev_priv->flush_queue, &entry);
+ for (;;) {
+ i810_dma_quiescent_emit(dev);
+ if (atomic_read(&dev_priv->flush_done) == 1) break;
+ curTime = __gettimeinmillis();
+ if (startTime == 0 || curTime < startTime /*wrap case*/) {
+ startTime = curTime;
+ } else if (curTime - startTime > timeout_millis) {
+ 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;
+ int ret = 0;
+ int startTime = 0;
+ int curTime = 0;
+ int timeout_millis = 3000;
+
+
+ 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);
+ for (;;) {
+ i810_dma_emit_flush(dev);
+ if (atomic_read(&dev_priv->flush_done) == 1) break;
+ curTime = __gettimeinmillis();
+ if (startTime == 0 || curTime < startTime /*wrap case*/) {
+ startTime = curTime;
+ } else if (curTime - startTime > timeout_millis) {
+ 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 +763,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 +787,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 +800,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 +816,183 @@ 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");
+ 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 ];
+
+ buf->used = args->used;
+
+ DRM_DEBUG("i810DmaGeneral idx %d used %d\n", args->idx, buf->used);
+
+ if (!buf->used) {
+ DRM_ERROR("0 length buffer\n");
+ i810_freelist_put(dev, buf);
+ return 0;
+ }
+
+ i810_dma_dispatch_general( dev, buf );
+ atomic_add(buf->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_i810_buf_priv_t *buf_priv;
+ drm_buf_t *buf;
+
+
+ buf = dma->buflist[ args->idx ];
+ buf->used = args->real_used;
+
+ DRM_DEBUG("i810DmaVertex idx %d used %d\n", args->idx, buf->used);
+
+ buf_priv = buf->dev_private;
+ buf_priv->vertex_real_idx = args->real_idx;
+ buf_priv->vertex_discard = args->discard;
+
+ i810_dma_dispatch_vertex( dev, buf);
+ atomic_add(buf->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);
+
+ retcode = i810DmaGeneral(dev, &general);
+ 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);
+
+ DRM_DEBUG("i810 dma vertex, idx %d used %d real_idx %d discard %d\n",
+ vertex.idx, vertex.real_used, vertex.real_idx,
+ vertex.discard);
+
+ retcode = i810DmaVertex(dev, &vertex);
+ 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);
+
+ /* 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_drv.c b/linux-core/i810_drv.c
index f33153a3..179b8714 100644
--- a/linux-core/i810_drv.c
+++ b/linux-core/i810_drv.c
@@ -33,11 +33,14 @@
#define EXPORT_SYMTAB
#include "drmP.h"
#include "i810_drv.h"
+#include "i810_dma.h"
+
+
EXPORT_SYMBOL(i810_init);
EXPORT_SYMBOL(i810_cleanup);
#define I810_NAME "i810"
-#define I810_DESC "Matrox g200/g400"
+#define I810_DESC "Intel I810"
#define I810_DATE "19991213"
#define I810_MAJOR 0
#define I810_MINOR 0
@@ -54,6 +57,7 @@ static struct file_operations i810_fops = {
mmap: drm_mmap,
read: drm_read,
fasync: drm_fasync,
+ poll: drm_poll,
};
static struct miscdevice i810_misc = {
@@ -80,13 +84,13 @@ static drm_ioctl_desc_t i810_ioctls[] = {
[DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)] = { i810_mapbufs, 1, 0 },
[DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = { i810_freebufs, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { drm_addctx, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { drm_rmctx, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { drm_modctx, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = { drm_getctx, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { drm_switchctx, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = { drm_newctx, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = { drm_resctx, 1, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { i810_addctx, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { i810_rmctx, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { i810_modctx, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = { i810_getctx, 1, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { i810_switchctx, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = { i810_newctx, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = { i810_resctx, 1, 0 },
[DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)] = { drm_adddraw, 1, 1 },
[DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)] = { drm_rmdraw, 1, 1 },
@@ -104,6 +108,11 @@ static drm_ioctl_desc_t i810_ioctls[] = {
[DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)] = { drm_agp_free, 1, 1 },
[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_I810_INIT)] = { i810_dma_init, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_I810_VERTEX)] = { i810_dma_vertex, 1, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_I810_DMA)] = { i810_dma_general,1, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_I810_FLUSH)] = { i810_flush_ioctl,1, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_I810_GETAGE)] = { i810_getage, 1, 0 },
};
#define I810_IOCTL_COUNT DRM_ARRAY_SIZE(i810_ioctls)
@@ -121,7 +130,7 @@ MODULE_PARM(i810, "s");
int init_module(void)
{
- printk("doing i810_init()\n");
+ DRM_DEBUG("doing i810_init()\n");
return i810_init();
}
@@ -364,7 +373,7 @@ int i810_init(void)
#ifdef MODULE
drm_parse_options(i810);
#endif
- printk("doing misc_register\n");
+ DRM_DEBUG("doing misc_register\n");
if ((retcode = misc_register(&i810_misc))) {
DRM_ERROR("Cannot register \"%s\"\n", I810_NAME);
return retcode;
@@ -372,13 +381,22 @@ int i810_init(void)
dev->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 +404,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 +431,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 +497,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 +637,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 0f5f42bb..d3dc6906 100644
--- a/linux-core/i810_drv.h
+++ b/linux-core/i810_drv.h
@@ -31,6 +31,32 @@
#ifndef _I810_DRV_H_
#define _I810_DRV_H_
+#include "i810_drm_public.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);
@@ -54,8 +80,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 +103,25 @@ 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);
+
+
#endif
diff --git a/linux-core/mga_drv.c b/linux-core/mga_drv.c
index 8bc25617..48041354 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/r128_drv.c b/linux-core/r128_drv.c
new file mode 100644
index 00000000..d477a70d
--- /dev/null
+++ b/linux-core/r128_drv.c
@@ -0,0 +1,712 @@
+/* r128_drv.c -- ATI Rage 128 driver -*- linux-c -*-
+ * Created: Mon Dec 13 09:47:27 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999, 2000 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 <faith@precisioninsight.com>
+ *
+ * $XFree86$
+ *
+ */
+
+#define EXPORT_SYMTAB
+#include "drmP.h"
+#include "r128_drv.h"
+EXPORT_SYMBOL(r128_init);
+EXPORT_SYMBOL(r128_cleanup);
+
+#define R128_NAME "r128"
+#define R128_DESC "r128"
+#define R128_DATE "19991213"
+#define R128_MAJOR 0
+#define R128_MINOR 0
+#define R128_PATCHLEVEL 1
+
+static drm_device_t r128_device;
+drm_ctx_t r128_res_ctx;
+
+static struct file_operations r128_fops = {
+ open: r128_open,
+ flush: drm_flush,
+ release: r128_release,
+ ioctl: r128_ioctl,
+ mmap: drm_mmap,
+ read: drm_read,
+ fasync: drm_fasync,
+ poll: drm_poll,
+};
+
+static struct miscdevice r128_misc = {
+ minor: MISC_DYNAMIC_MINOR,
+ name: R128_NAME,
+ fops: &r128_fops,
+};
+
+static drm_ioctl_desc_t r128_ioctls[] = {
+ [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = { r128_version, 0, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = { drm_getunique, 0, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)] = { drm_getmagic, 0, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = { drm_irq_busid, 0, 1 },
+
+ [DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)] = { drm_setunique, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_BLOCK)] = { drm_block, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)] = { drm_unblock, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)] = { drm_authmagic, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)] = { drm_addmap, 1, 1 },
+
+ [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { r128_addctx, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { r128_rmctx, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { r128_modctx, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = { r128_getctx, 1, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { r128_switchctx, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = { r128_newctx, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = { r128_resctx, 1, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)] = { drm_adddraw, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)] = { drm_rmdraw, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_LOCK)] = { r128_lock, 1, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = { r128_unlock, 1, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { drm_finish, 1, 0 },
+
+ [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, 0 },
+ [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_bind, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = { drm_agp_unbind, 1, 1 },
+};
+#define R128_IOCTL_COUNT DRM_ARRAY_SIZE(r128_ioctls)
+
+#ifdef MODULE
+int init_module(void);
+void cleanup_module(void);
+static char *r128 = NULL;
+
+MODULE_AUTHOR("Precision Insight, Inc., Cedar Park, Texas.");
+MODULE_DESCRIPTION("r128");
+MODULE_PARM(r128, "s");
+
+/* init_module is called when insmod is used to load the module */
+
+int init_module(void)
+{
+ return r128_init();
+}
+
+/* cleanup_module is called when rmmod is used to unload the module */
+
+void cleanup_module(void)
+{
+ r128_cleanup();
+}
+#endif
+
+#ifndef MODULE
+/* r128_setup is called by the kernel to parse command-line options passed
+ * via the boot-loader (e.g., LILO). It calls the insmod option routine,
+ * drm_parse_drm.
+ *
+ * This is not currently supported, since it requires changes to
+ * linux/init/main.c. */
+
+
+void __init r128_setup(char *str, int *ints)
+{
+ if (ints[0] != 0) {
+ DRM_ERROR("Illegal command line format, ignored\n");
+ return;
+ }
+ drm_parse_options(str);
+}
+#endif
+
+static int r128_setup(drm_device_t *dev)
+{
+ int i;
+
+ atomic_set(&dev->ioctl_count, 0);
+ atomic_set(&dev->vma_count, 0);
+ dev->buf_use = 0;
+ atomic_set(&dev->buf_alloc, 0);
+
+ atomic_set(&dev->total_open, 0);
+ atomic_set(&dev->total_close, 0);
+ atomic_set(&dev->total_ioctl, 0);
+ atomic_set(&dev->total_irq, 0);
+ atomic_set(&dev->total_ctx, 0);
+ atomic_set(&dev->total_locks, 0);
+ atomic_set(&dev->total_unlocks, 0);
+ atomic_set(&dev->total_contends, 0);
+ atomic_set(&dev->total_sleeps, 0);
+
+ for (i = 0; i < DRM_HASH_SIZE; i++) {
+ dev->magiclist[i].head = NULL;
+ dev->magiclist[i].tail = NULL;
+ }
+ dev->maplist = NULL;
+ dev->map_count = 0;
+ dev->vmalist = NULL;
+ dev->lock.hw_lock = NULL;
+ init_waitqueue_head(&dev->lock.lock_queue);
+ dev->queue_count = 0;
+ dev->queue_reserved = 0;
+ dev->queue_slots = 0;
+ dev->queuelist = NULL;
+ dev->irq = 0;
+ dev->context_flag = 0;
+ dev->interrupt_flag = 0;
+ dev->dma = 0;
+ dev->dma_flag = 0;
+ dev->last_context = 0;
+ dev->last_switch = 0;
+ dev->last_checked = 0;
+ init_timer(&dev->timer);
+ init_waitqueue_head(&dev->context_wait);
+
+ dev->ctx_start = 0;
+ dev->lck_start = 0;
+
+ dev->buf_rp = dev->buf;
+ dev->buf_wp = dev->buf;
+ dev->buf_end = dev->buf + DRM_BSZ;
+ dev->buf_async = NULL;
+ init_waitqueue_head(&dev->buf_readers);
+ init_waitqueue_head(&dev->buf_writers);
+
+ r128_res_ctx.handle=-1;
+
+ DRM_DEBUG("\n");
+
+ /* The kernel's context could be created here, but is now created
+ in drm_dma_enqueue. This is more resource-efficient for
+ hardware that does not do DMA, but may mean that
+ drm_select_queue fails between the time the interrupt is
+ initialized and the time the queues are initialized. */
+
+ return 0;
+}
+
+
+static int r128_takedown(drm_device_t *dev)
+{
+ int i;
+ drm_magic_entry_t *pt, *next;
+ drm_map_t *map;
+ drm_vma_entry_t *vma, *vma_next;
+
+ DRM_DEBUG("\n");
+
+ down(&dev->struct_sem);
+ del_timer(&dev->timer);
+
+ if (dev->devname) {
+ drm_free(dev->devname, strlen(dev->devname)+1, DRM_MEM_DRIVER);
+ dev->devname = NULL;
+ }
+
+ if (dev->unique) {
+ drm_free(dev->unique, strlen(dev->unique)+1, DRM_MEM_DRIVER);
+ dev->unique = NULL;
+ dev->unique_len = 0;
+ }
+ /* Clear pid list */
+ for (i = 0; i < DRM_HASH_SIZE; i++) {
+ for (pt = dev->magiclist[i].head; pt; pt = next) {
+ next = pt->next;
+ drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
+ }
+ dev->magiclist[i].head = dev->magiclist[i].tail = NULL;
+ }
+
+ /* Clear AGP information */
+ if (dev->agp) {
+ drm_agp_mem_t *entry;
+ drm_agp_mem_t *nexte;
+
+ /* Remove AGP resources, but leave dev->agp
+ intact until r128_cleanup is called. */
+ for (entry = dev->agp->memory; entry; entry = nexte) {
+ nexte = entry->next;
+ if (entry->bound) drm_unbind_agp(entry->memory);
+ drm_free_agp(entry->memory, entry->pages);
+ drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
+ }
+ dev->agp->memory = NULL;
+
+ if (dev->agp->acquired && drm_agp.release)
+ (*drm_agp.release)();
+
+ dev->agp->acquired = 0;
+ dev->agp->enabled = 0;
+ }
+
+ /* Clear vma list (only built for debugging) */
+ if (dev->vmalist) {
+ for (vma = dev->vmalist; vma; vma = vma_next) {
+ vma_next = vma->next;
+ drm_free(vma, sizeof(*vma), DRM_MEM_VMAS);
+ }
+ dev->vmalist = NULL;
+ }
+
+ /* Clear map area and mtrr information */
+ if (dev->maplist) {
+ for (i = 0; i < dev->map_count; i++) {
+ map = dev->maplist[i];
+ switch (map->type) {
+ case _DRM_REGISTERS:
+ case _DRM_FRAME_BUFFER:
+#ifdef CONFIG_MTRR
+ if (map->mtrr >= 0) {
+ int retcode;
+ retcode = mtrr_del(map->mtrr,
+ map->offset,
+ map->size);
+ DRM_DEBUG("mtrr_del = %d\n", retcode);
+ }
+#endif
+ drm_ioremapfree(map->handle, map->size);
+ break;
+ case _DRM_SHM:
+ drm_free_pages((unsigned long)map->handle,
+ drm_order(map->size)
+ - 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);
+ }
+ drm_free(dev->maplist,
+ dev->map_count * sizeof(*dev->maplist),
+ DRM_MEM_MAPS);
+ dev->maplist = NULL;
+ dev->map_count = 0;
+ }
+
+ if (dev->lock.hw_lock) {
+ dev->lock.hw_lock = NULL; /* SHM removed */
+ dev->lock.pid = 0;
+ wake_up_interruptible(&dev->lock.lock_queue);
+ }
+ up(&dev->struct_sem);
+
+ return 0;
+}
+
+/* r128_init is called via init_module at module load time, or via
+ * linux/init/main.c (this is not currently supported). */
+
+int r128_init(void)
+{
+ int retcode;
+ drm_device_t *dev = &r128_device;
+
+ DRM_DEBUG("\n");
+
+ memset((void *)dev, 0, sizeof(*dev));
+ dev->count_lock = SPIN_LOCK_UNLOCKED;
+ sema_init(&dev->struct_sem, 1);
+
+#ifdef MODULE
+ drm_parse_options(r128);
+#endif
+
+ if ((retcode = misc_register(&r128_misc))) {
+ DRM_ERROR("Cannot register \"%s\"\n", R128_NAME);
+ return retcode;
+ }
+ dev->device = MKDEV(MISC_MAJOR, r128_misc.minor);
+ dev->name = R128_NAME;
+
+ drm_mem_init();
+ drm_proc_init(dev);
+
+ dev->agp = drm_agp_init();
+
+#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
+
+ if((retcode = drm_ctxbitmap_init(dev))) {
+ DRM_ERROR("Cannot allocate memory for context bitmap.\n");
+ drm_proc_cleanup();
+ misc_deregister(&r128_misc);
+ r128_takedown(dev);
+ return retcode;
+ }
+
+ DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
+ R128_NAME,
+ R128_MAJOR,
+ R128_MINOR,
+ R128_PATCHLEVEL,
+ R128_DATE,
+ r128_misc.minor);
+
+ return 0;
+}
+
+/* r128_cleanup is called via cleanup_module at module unload time. */
+
+void r128_cleanup(void)
+{
+ drm_device_t *dev = &r128_device;
+
+ DRM_DEBUG("\n");
+
+ drm_proc_cleanup();
+ if (misc_deregister(&r128_misc)) {
+ DRM_ERROR("Cannot unload module\n");
+ } else {
+ DRM_INFO("Module unloaded\n");
+ }
+ drm_ctxbitmap_cleanup(dev);
+ r128_takedown(dev);
+ if (dev->agp) {
+ /* FIXME -- free other information, too */
+ drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS);
+ dev->agp = NULL;
+ }
+}
+
+int r128_version(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_version_t version;
+ int len;
+
+ copy_from_user_ret(&version,
+ (drm_version_t *)arg,
+ sizeof(version),
+ -EFAULT);
+
+#define DRM_COPY(name,value) \
+ len = strlen(value); \
+ if (len > name##_len) len = name##_len; \
+ name##_len = strlen(value); \
+ if (len && name) { \
+ copy_to_user_ret(name, value, len, -EFAULT); \
+ }
+
+ version.version_major = R128_MAJOR;
+ version.version_minor = R128_MINOR;
+ version.version_patchlevel = R128_PATCHLEVEL;
+
+ DRM_COPY(version.name, R128_NAME);
+ DRM_COPY(version.date, R128_DATE);
+ DRM_COPY(version.desc, R128_DESC);
+
+ copy_to_user_ret((drm_version_t *)arg,
+ &version,
+ sizeof(version),
+ -EFAULT);
+ return 0;
+}
+
+int r128_open(struct inode *inode, struct file *filp)
+{
+ drm_device_t *dev = &r128_device;
+ int retcode = 0;
+
+ DRM_DEBUG("open_count = %d\n", dev->open_count);
+ if (!(retcode = drm_open_helper(inode, filp, dev))) {
+ MOD_INC_USE_COUNT;
+ atomic_inc(&dev->total_open);
+ spin_lock(&dev->count_lock);
+ if (!dev->open_count++) {
+ spin_unlock(&dev->count_lock);
+ return r128_setup(dev);
+ }
+ spin_unlock(&dev->count_lock);
+ }
+ return retcode;
+}
+
+int r128_release(struct inode *inode, struct file *filp)
+{
+ drm_file_t *priv = filp->private_data;
+ 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;
+ }
+ spin_unlock(&dev->count_lock);
+ return r128_takedown(dev);
+ }
+ spin_unlock(&dev->count_lock);
+ }
+ return retcode;
+}
+
+/* r128_ioctl is called whenever a process performs an ioctl on /dev/drm. */
+
+int r128_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ int nr = DRM_IOCTL_NR(cmd);
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ int retcode = 0;
+ drm_ioctl_desc_t *ioctl;
+ drm_ioctl_t *func;
+
+ atomic_inc(&dev->ioctl_count);
+ atomic_inc(&dev->total_ioctl);
+ ++priv->ioctl_count;
+
+ DRM_DEBUG("pid = %d, cmd = 0x%02x, nr = 0x%02x, dev 0x%x, auth = %d\n",
+ current->pid, cmd, nr, dev->device, priv->authenticated);
+
+ if (nr >= R128_IOCTL_COUNT) {
+ retcode = -EINVAL;
+ } else {
+ ioctl = &r128_ioctls[nr];
+ func = ioctl->func;
+
+ if (!func) {
+ DRM_DEBUG("no function\n");
+ retcode = -EINVAL;
+ } else if ((ioctl->root_only && !capable(CAP_SYS_ADMIN))
+ || (ioctl->auth_needed && !priv->authenticated)) {
+ retcode = -EACCES;
+ } else {
+ retcode = (func)(inode, filp, cmd, arg);
+ }
+ }
+
+ atomic_dec(&dev->ioctl_count);
+ return retcode;
+}
+
+int r128_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;
+#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);
+
+ if (lock.context == DRM_KERNEL_CONTEXT) {
+ DRM_ERROR("Process %d using kernel context %d\n",
+ 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 0
+ /* dev->queue_count == 0 right now for
+ r128. FIXME? */
+ if (lock.context < 0 || lock.context >= dev->queue_count)
+ return -EINVAL;
+#endif
+
+ if (!ret) {
+#if 0
+ if (_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)
+ != lock.context) {
+ long j = jiffies - dev->lock.lock_time;
+
+ if (lock.context == r128_res_ctx.handle &&
+ j >= 0 && j < DRM_LOCK_SLICE) {
+ /* Can't take lock if we just had it and
+ there is contention. */
+ DRM_DEBUG("%d (pid %d) delayed j=%d dev=%d jiffies=%d\n",
+ lock.context, current->pid, j,
+ dev->lock.lock_time, jiffies);
+ current->state = TASK_INTERRUPTIBLE;
+ current->policy |= SCHED_YIELD;
+ schedule_timeout(DRM_LOCK_SLICE-j);
+ DRM_DEBUG("jiffies=%d\n", jiffies);
+ }
+ }
+#endif
+ add_wait_queue(&dev->lock.lock_queue, &entry);
+ for (;;) {
+ if (!dev->lock.hw_lock) {
+ /* Device has been unregistered */
+ ret = -EINTR;
+ break;
+ }
+ if (drm_lock_take(&dev->lock.hw_lock->lock,
+ lock.context)) {
+ dev->lock.pid = current->pid;
+ dev->lock.lock_time = jiffies;
+ atomic_inc(&dev->total_locks);
+ break; /* Got lock */
+ }
+
+ /* Contention */
+ atomic_inc(&dev->total_sleeps);
+ current->state = TASK_INTERRUPTIBLE;
+#if 1
+ current->policy |= SCHED_YIELD;
+#endif
+ schedule();
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&dev->lock.lock_queue, &entry);
+ }
+
+#if 0
+ if (!ret && dev->last_context != lock.context &&
+ lock.context != r128_res_ctx.handle &&
+ dev->last_context != r128_res_ctx.handle) {
+ add_wait_queue(&dev->context_wait, &entry);
+ current->state = TASK_INTERRUPTIBLE;
+ /* PRE: dev->last_context != lock.context */
+ r128_context_switch(dev, dev->last_context, lock.context);
+ /* POST: we will wait for the context
+ switch and will dispatch on a later call
+ when dev->last_context == lock.context
+ NOTE WE HOLD THE LOCK THROUGHOUT THIS
+ TIME! */
+ current->policy |= SCHED_YIELD;
+ schedule();
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&dev->context_wait, &entry);
+ if (signal_pending(current)) {
+ ret = -EINTR;
+ } else if (dev->last_context != lock.context) {
+ DRM_ERROR("Context mismatch: %d %d\n",
+ dev->last_context, lock.context);
+ }
+ }
+#endif
+
+ if (!ret) {
+ if (lock.flags & _DRM_LOCK_READY) {
+ /* Wait for space in DMA/FIFO */
+ }
+ if (lock.flags & _DRM_LOCK_QUIESCENT) {
+ /* Make hardware quiescent */
+#if 0
+ r128_quiescent(dev);
+#endif
+ }
+ }
+
+#if 0
+ DRM_ERROR("pid = %5d, old counter = %5ld\n",
+ current->pid, current->counter);
+#endif
+ if (lock.context != r128_res_ctx.handle) {
+ current->counter = 5;
+ current->priority = DEF_PRIORITY/4;
+ }
+#if 0
+ while (current->counter > 25)
+ current->counter >>= 1; /* decrease time slice */
+ DRM_ERROR("pid = %5d, new counter = %5ld\n",
+ current->pid, current->counter);
+#endif
+ DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock");
+
+#if DRM_DMA_HISTOGRAM
+ atomic_inc(&dev->histo.lacq[drm_histogram_slot(get_cycles() - start)]);
+#endif
+
+ return ret;
+}
+
+
+int r128_unlock(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;
+
+ copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT);
+
+ if (lock.context == DRM_KERNEL_CONTEXT) {
+ DRM_ERROR("Process %d using kernel context %d\n",
+ current->pid, lock.context);
+ return -EINVAL;
+ }
+
+ DRM_DEBUG("%d frees lock (%d holds)\n",
+ lock.context,
+ _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+ 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);
+ /* FIXME: Try to send data to card here */
+ if (!dev->context_flag) {
+ if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
+ DRM_KERNEL_CONTEXT)) {
+ DRM_ERROR("\n");
+ }
+ }
+
+#if 0
+ current->policy |= SCHED_YIELD;
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(1000);
+#endif
+
+ if (lock.context != r128_res_ctx.handle) {
+ current->counter = 5;
+ current->priority = DEF_PRIORITY;
+ }
+#if 0
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(10);
+#endif
+
+ return 0;
+}
diff --git a/linux-core/tdfx_drv.c b/linux-core/tdfx_drv.c
index 57c1c719..fb7a997b 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 44d75c48..a169473a 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,12 @@ 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
+
+r128.o: r128_drv.o r128_context.o $(L_TARGET)
+ $(LD) $(LD_RFLAG) -r -o $@ r128_drv.o r128_context.o -L. -ldrm
diff --git a/linux/Makefile.linux b/linux/Makefile.linux
index 8a41f880..17c65454 100644
--- a/linux/Makefile.linux
+++ b/linux/Makefile.linux
@@ -1,8 +1,7 @@
# Makefile -- For the Direct Rendering Manager module (drm)
# Created: Mon Jan 4 09:26:53 1999 by faith@precisioninsight.com
-# Revised: Sun Feb 13 23:15:59 2000 by kevin@precisioninsight.com
#
-# Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+# Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
# All rights reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a
@@ -31,12 +30,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 +49,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 +105,30 @@ 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 r128.o
+
+MGAOBJS= mga_drv.o mga_dma.o mga_bufs.o mga_state.o mga_context.o
+MGAHEADERS= mga_drv.h mga_drm_public.h $(DRMHEADERS)
+
+I810OBJS= i810_drv.o i810_dma.o i810_bufs.o i810_context.o
+I810HEADERS= i810_drv.h i810_drm_public.h $(DRMHEADERS)
+
+R128OBJS= r128_drv.o r128_context.o
+R128HEADERS= r128_drv.h $(DRMHEADERS)
+endif
+
+all::;@echo KERNEL HEADERS IN $(TREE): SMP=${SMP} MODVERSIONS=${MODVERSIONS} \
+ AGP=${AGP}
all:: $(LIBS) $(MODS) $(PROGS)
endif
@@ -116,6 +142,7 @@ ifeq ($(MODVERSIONS),1)
MODCFLAGS += -DMODVERSIONS -include $(TREE)/linux/modversions.h
endif
+
# **** End of configuration
libdrm.a: $(DRMOBJS)
@@ -128,6 +155,17 @@ 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 $@
+
+r128.o: $(R128OBJS) $(LIBS)
+ $(LD) -r $^ -o $@
+endif
+
drmstat: $(PROGOBJS)
$(CC) $(PRGCFLAGS) $^ $(PRGLIBS) -o $@
@@ -149,8 +187,12 @@ ChangeLog:
$(DRMOBJS): $(DRMHEADERS)
$(GAMMAOBJS): $(GAMMAHEADERS)
$(TDFXOBJS): $(TDFXHEADERS)
+ifeq ($(AGP),1)
+$(MGAOBJS): $(MGAHEADERS)
+$(I810OBJS): $(I810HEADERS)
+$(R128OBJS): $(R128HEADERS)
+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 fb58154d..d60edc2e 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;
@@ -253,9 +255,15 @@ int drm_agp_free(struct inode *inode, struct file *filp, unsigned int cmd,
-EFAULT);
if (!(entry = drm_agp_lookup_entry(dev, request.handle)))
return -EINVAL;
+#if 0
if (entry->bound) drm_unbind_agp(entry->memory);
- entry->prev->next = entry->next;
- entry->next->prev = entry->prev;
+#endif
+ if(entry->prev) entry->prev->next = entry->next;
+ if(entry->next) entry->next->prev = entry->prev;
+ if((entry->next == NULL) &&
+ (entry->prev == NULL)) {
+ dev->agp->memory = NULL;
+ }
drm_free_agp(entry->memory, entry->pages);
drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
return 0;
@@ -269,15 +277,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 85244c7d..7902f0cc 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 f67209d4..c3e64a31 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;
@@ -72,7 +72,7 @@ int drm_ctxbitmap_init(drm_device_t *dev)
memset((void *) dev->ctx_bitmap, 0, PAGE_SIZE * 4);
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;
diff --git a/linux/dma.c b/linux/dma.c
index 8291e52e..37ab674f 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 7b8e8826..ebc6f7e7 100644
--- a/linux/drm.h
+++ b/linux/drm.h
@@ -101,7 +101,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 +166,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 +241,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 +312,14 @@ 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)
+
+/* 0x40 is reserved for mga dma init */
#endif
diff --git a/linux/drmP.h b/linux/drmP.h
index 312fba36..c00d3bb0 100644
--- a/linux/drmP.h
+++ b/linux/drmP.h
@@ -48,8 +48,12 @@
#ifdef CONFIG_MTRR
#include <asm/mtrr.h>
#endif
+#ifdef DRM_AGP
+#include <linux/types.h>
+#include <linux/agp_backend.h>
+#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
#include <linux/poll.h>
#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 * 4 * 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 ce970835..a3c2bd4a 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 49455b43..be041f14 100644
--- a/linux/i810_bufs.c
+++ b/linux/i810_bufs.c
@@ -32,6 +32,8 @@
#define __NO_VERSION__
#include "drmP.h"
+#include "i810_drv.h"
+#include "i810_dma.h"
#include "linux/un.h"
int i810_addbufs_agp(struct inode *inode, struct file *filp, unsigned int cmd,
@@ -99,33 +101,38 @@ int i810_addbufs_agp(struct inode *inode, struct file *filp, unsigned int cmd,
entry->buf_size = size;
entry->page_order = page_order;
+ offset = 0;
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;
+ 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,
@@ -137,8 +144,7 @@ int i810_addbufs_agp(struct inode *inode, struct file *filp, unsigned int cmd,
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);
-
+ 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]);
@@ -155,170 +161,10 @@ int i810_addbufs_agp(struct inode *inode, struct file *filp, unsigned int cmd,
-EFAULT);
atomic_dec(&dev->buf_alloc);
+ dma->flags = _DRM_DMA_USE_AGP;
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;
-
- 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;
-
- 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 */
-
- 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;
-
- 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->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->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;
-#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->seg_count += entry->seg_count;
- dma->page_count += entry->seg_count << page_order;
- 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(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long arg)
{
@@ -332,7 +178,7 @@ int i810_addbufs(struct inode *inode, struct file *filp, unsigned int cmd,
if(request.flags & _DRM_AGP_BUFFER)
return i810_addbufs_agp(inode, filp, cmd, arg);
else
- return i810_addbufs_pci(inode, filp, cmd, arg);
+ return -EINVAL;
}
int i810_infobufs(struct inode *inode, struct file *filp, unsigned int cmd,
@@ -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,70 +362,79 @@ 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) {
+ DRM_DEBUG("dma->flags : %lx\n", dma->flags);
+ if (request.count >= dma->buf_count) {
if(dma->flags & _DRM_DMA_USE_AGP) {
- /* This is an ugly vicious hack */
+ drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
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) {
+
+ 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(&current->mm->mmap_sem);
virtual = do_mmap(filp, 0, map->size, PROT_READ|PROT_WRITE,
- MAP_SHARED, (unsigned long)map->handle);
- }
- else {
+ MAP_SHARED, (unsigned long)map->offset);
+ up(&current->mm->mmap_sem);
+ } else {
+ down(&current->mm->mmap_sem);
virtual = do_mmap(filp, 0, dma->byte_count,
PROT_READ|PROT_WRITE, MAP_SHARED, 0);
+ up(&current->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;
+ }
}
- if (virtual > -1024UL) {
- /* Real error */
- 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);
-
- copy_to_user_ret((drm_buf_map_t *)arg,
- &request,
- sizeof(request),
- -EFAULT);
+ 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);
- return retcode;
+ 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 00000000..5503edf2
--- /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 <faith@precisioninsight.com>
+ *
+ * $XFree86$
+ *
+ */
+
+#include <linux/sched.h>
+
+#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 09959b65..e79f7ff5 100644
--- a/linux/i810_dma.c
+++ b/linux/i810_dma.c
@@ -24,7 +24,8 @@
* DEALINGS IN THE SOFTWARE.
*
* Authors: Rickard E. (Rik) Faith <faith@precisioninsight.com>
- * Jeff Hartmann <jhartmann@precisioninsight.com>
+ * Jeff Hartmann <jhartmann@precisioninsight.com>
+ * Keith Whitwell <keithw@precisioninsight.com>
*
* $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 $
*
@@ -32,9 +33,15 @@
#define __NO_VERSION__
#include "drmP.h"
+#include "i810_drm_public.h"
#include "i810_drv.h"
+#include "i810_dma.h"
#include <linux/interrupt.h> /* For task queue support */
+#include <linux/time.h> /* For do_gettimeofday */
+
+#define I810_BUF_FREE 1
+#define I810_BUF_USED 0
#define I810_REG(reg) 2
#define I810_BASE(reg) ((unsigned long) \
@@ -43,544 +50,460 @@
#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, 0); \
+ 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 __gettimeinmillis(void)
{
- 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_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;
- }
+ int millis;
+
+ millis = ((jiffies / HZ) * 1000) + ((jiffies % HZ) * (1000 / HZ));
+ return millis;
+}
- 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;
- }
+static int i810_wait_ring(drm_device_t *dev, int n, int timeout_millis)
+{
+ drm_i810_private_t *dev_priv = dev->dev_private;
+ drm_i810_ring_buffer_t *ring = &(dev_priv->ring);
+ int iters = 0;
+ int startTime = 0;
+ int curTime = 0;
+
+ if (timeout_millis == 0) timeout_millis = 3000;
+
+ while (ring->space < n) {
+ int i;
- 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);
+ 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++;
+ curTime = __gettimeinmillis();
+ if (startTime == 0 || curTime < startTime /*wrap case*/) {
+ startTime = curTime;
+ } else if (curTime - startTime > timeout_millis) {
+ DRM_ERROR("space: %d wanted %d\n", ring->space, n);
+ DRM_ERROR("lockup\n");
+ goto out_wait_ring;
}
- } 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;
- }
- }
-
- 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);
- }
-
- if ((retcode = drm_dma_enqueue(dev, d))) {
- if (d->flags & _DRM_DMA_BLOCK)
- remove_wait_queue(&last_buf->dma_wait, &entry);
- return retcode;
- }
+ 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;
- 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 inline void i810_dma_dispatch_general(drm_device_t *dev, drm_buf_t *buf)
{
- 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);
-
- 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;
- }
-
- 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;
- }
+ 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;
+ int length = buf->used;
+ 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( "length : 0x%x\n", length);
+ DRM_DEBUG( "start + length - 4 : 0x%lx\n", start + length - 4);
+ i810_kernel_lost_context(dev);
+
+ BEGIN_LP_RING(10);
+ OUT_RING( CMD_OP_BATCH_BUFFER );
+ OUT_RING( start | BB1_PROTECTED );
+ OUT_RING( start + length - 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.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");
+static inline void i810_dma_dispatch_vertex(drm_device_t *dev, drm_buf_t *buf)
+{
+ drm_i810_private_t *dev_priv = dev->dev_private;
+ drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+ drm_buf_t *real_buf = dev->dma->buflist[ buf_priv->vertex_real_idx ];
+ drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
+ xf86drmClipRectRec *box = sarea_priv->boxes;
+ int nbox = sarea_priv->nbox;
+ unsigned long address = (unsigned long)real_buf->bus_address;
+ unsigned long start = address - dev->agp->base;
+ int length = buf->used;
+ int i = 0;
+ RING_LOCALS;
- retcode = i810_dma_priority(dev, &d);
- }
+
+ if(nbox > I810_NR_SAREA_CLIPRECTS) nbox = I810_NR_SAREA_CLIPRECTS;
+
+ DRM_DEBUG("dispatch vertex addr 0x%lx, length 0x%x nbox %d\n",
+ address, length, buf_priv->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( "length : %d\n", length);
+ DRM_DEBUG( "start + length - 4 : %ld\n", start + length - 4);
+ i810_kernel_lost_context(dev);
+
+ if (!buf_priv->vertex_discard) {
+ 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 + length - 4 );
+ OUT_RING( 0 );
+ ADVANCE_LP_RING();
+
+ } while (++i < nbox);
+ }
+
+ BEGIN_LP_RING(8);
+ 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 );
+ OUT_RING( 0 );
+ ADVANCE_LP_RING();
+}
- d.granted_count = 0;
- if (!retcode && d.request_count) {
- retcode = drm_dma_get_buffers(dev, &d);
- }
+/* 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);
+}
- DRM_DEBUG("%d returning, granted = %d\n",
- current->pid, d.granted_count);
- copy_to_user_ret((drm_dma_t *)arg, &d, sizeof(d), -EFAULT);
+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;
- printk("i810_dma end (granted)\n");
- return retcode;
+ 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 +514,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 +527,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 +553,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 +572,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 +599,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 +618,143 @@ 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;
+ int startTime = 0;
+ int curTime = 0;
+ int timeout_millis = 3000;
+
+
+ if(dev_priv == NULL) {
+ return;
+ }
+ atomic_set(&dev_priv->flush_done, 0);
+ current->state = TASK_INTERRUPTIBLE;
+ add_wait_queue(&dev_priv->flush_queue, &entry);
+ for (;;) {
+ i810_dma_quiescent_emit(dev);
+ if (atomic_read(&dev_priv->flush_done) == 1) break;
+ curTime = __gettimeinmillis();
+ if (startTime == 0 || curTime < startTime /*wrap case*/) {
+ startTime = curTime;
+ } else if (curTime - startTime > timeout_millis) {
+ 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;
+ int ret = 0;
+ int startTime = 0;
+ int curTime = 0;
+ int timeout_millis = 3000;
+
+
+ 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);
+ for (;;) {
+ i810_dma_emit_flush(dev);
+ if (atomic_read(&dev_priv->flush_done) == 1) break;
+ curTime = __gettimeinmillis();
+ if (startTime == 0 || curTime < startTime /*wrap case*/) {
+ startTime = curTime;
+ } else if (curTime - startTime > timeout_millis) {
+ 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 +763,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 +787,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 +800,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 +816,183 @@ 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");
+ 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 ];
+
+ buf->used = args->used;
+
+ DRM_DEBUG("i810DmaGeneral idx %d used %d\n", args->idx, buf->used);
+
+ if (!buf->used) {
+ DRM_ERROR("0 length buffer\n");
+ i810_freelist_put(dev, buf);
+ return 0;
+ }
+
+ i810_dma_dispatch_general( dev, buf );
+ atomic_add(buf->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_i810_buf_priv_t *buf_priv;
+ drm_buf_t *buf;
+
+
+ buf = dma->buflist[ args->idx ];
+ buf->used = args->real_used;
+
+ DRM_DEBUG("i810DmaVertex idx %d used %d\n", args->idx, buf->used);
+
+ buf_priv = buf->dev_private;
+ buf_priv->vertex_real_idx = args->real_idx;
+ buf_priv->vertex_discard = args->discard;
+
+ i810_dma_dispatch_vertex( dev, buf);
+ atomic_add(buf->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);
+
+ retcode = i810DmaGeneral(dev, &general);
+ 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);
+
+ DRM_DEBUG("i810 dma vertex, idx %d used %d real_idx %d discard %d\n",
+ vertex.idx, vertex.real_used, vertex.real_idx,
+ vertex.discard);
+
+ retcode = i810DmaVertex(dev, &vertex);
+ 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);
+
+ /* 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_dma.h b/linux/i810_dma.h
new file mode 100644
index 00000000..0f79b6ab
--- /dev/null
+++ b/linux/i810_dma.h
@@ -0,0 +1,118 @@
+/* i810_dma.h -- DMA support for the i810 -*- linux-c -*-
+ *
+ * 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 <keithw@precisioninsight.com>
+ *
+ * $XFree86$
+ *
+ */
+
+
+#ifndef I810_DMA_H
+#define I810_DMA_H
+
+#include "i810_drm_public.h"
+
+
+/* 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 {
+ int vertex_real_idx;
+ int vertex_discard;
+ u32 *in_use;
+ int my_use_idx;
+ unsigned int nbox;
+ xf86drmClipRectRec boxes[I810_NR_SAREA_CLIPRECTS];
+} 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/i810_drm_public.h b/linux/i810_drm_public.h
new file mode 100644
index 00000000..7213def1
--- /dev/null
+++ b/linux/i810_drm_public.h
@@ -0,0 +1,139 @@
+/* i810_drm_public.h -- Public header for the i810 driver -*- linux-c -*-
+ * Created: Mon Dec 13 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 <jhartmann@precisioninsight.com>
+ * Keith Whitwell <keithw@precisioninsight.com>
+ *
+ * $XFree86$
+ */
+
+#ifndef _I810_DRM_H_
+#define _I810_DRM_H_
+
+typedef struct drm_i810_init {
+ enum {
+ I810_INIT_DMA = 0x01,
+ I810_CLEANUP_DMA = 0x02
+ } func;
+ int ring_map_idx;
+ int buffer_map_idx;
+ int sarea_priv_offset;
+ unsigned long ring_start;
+ unsigned long ring_end;
+ unsigned long ring_size;
+
+} drm_i810_init_t;
+
+typedef struct _xf86drmClipRectRec {
+ unsigned short x1;
+ unsigned short y1;
+ unsigned short x2;
+ unsigned short y2;
+} xf86drmClipRectRec;
+
+/* Might one day want to support the client-side ringbuffer code again.
+ */
+
+#define I810_USE_BATCH 1
+
+#define I810_DMA_BUF_ORDER 12
+#define I810_DMA_BUF_SZ (1<<I810_DMA_BUF_ORDER)
+#define I810_DMA_BUF_NR 256
+
+#define I810_NR_SAREA_CLIPRECTS 2
+
+/* Each region is a minimum of 64k, and there are at most 64 of them.
+ */
+#define I810_NR_TEX_REGIONS 64
+#define I810_LOG_MIN_TEX_REGION_SIZE 16
+
+typedef struct {
+ unsigned char next, prev; /* indices to form a circular LRU */
+ unsigned char in_use; /* owned by a client, or free? */
+ int age; /* tracked by clients to update local LRU's */
+} i810TexRegion;
+
+typedef struct {
+ unsigned int nbox;
+ xf86drmClipRectRec boxes[I810_NR_SAREA_CLIPRECTS];
+
+ /* Maintain an LRU of contiguous regions of texture space. If
+ * you think you own a region of texture memory, and it has an
+ * age different to the one you set, then you are mistaken and
+ * it has been stolen by another client. If global texAge
+ * hasn't changed, there is no need to walk the list.
+ *
+ * These regions can be used as a proxy for the fine-grained
+ * texture information of other clients - by maintaining them
+ * in the same lru which is used to age their own textures,
+ * clients have an approximate lru for the whole of global
+ * texture space, and can make informed decisions as to which
+ * areas to kick out. There is no need to choose whether to
+ * kick out your own texture or someone else's - simply eject
+ * them all in LRU order.
+ */
+ i810TexRegion texList[I810_NR_TEX_REGIONS+1]; /* Last elt is sentinal */
+
+ int texAge; /* last time texture was uploaded */
+
+ int last_enqueue; /* last time a buffer was enqueued */
+ int last_dispatch; /* age of the most recently dispatched buffer */
+ int last_quiescent; /* */
+
+ int ctxOwner; /* last context to upload state */
+} drm_i810_sarea_t;
+
+
+typedef struct {
+ int idx;
+ int used;
+ int age;
+} drm_i810_general_t;
+
+
+/* These may be placeholders if we have more cliprects than
+ * I810_NR_SAREA_CLIPRECTS. In that case, idx != real_idx; idx is the
+ * number of a placeholder buffer, real_idx is the real buffer to be
+ * rendered multiple times.
+ *
+ * This is a hack to work around the fact that the drm considers
+ * buffers to be only in a single state (ie on a single queue).
+ */
+typedef struct {
+ int idx; /* buffer to queue and free on completion */
+ int real_idx; /* buffer to execute */
+ int real_used; /* buf->used in for real buffer */
+ int discard; /* don't execute the commands */
+ int age;
+} drm_i810_vertex_t;
+
+
+
+#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 /* _I810_DRM_H_ */
diff --git a/linux/i810_drv.c b/linux/i810_drv.c
index f33153a3..179b8714 100644
--- a/linux/i810_drv.c
+++ b/linux/i810_drv.c
@@ -33,11 +33,14 @@
#define EXPORT_SYMTAB
#include "drmP.h"
#include "i810_drv.h"
+#include "i810_dma.h"
+
+
EXPORT_SYMBOL(i810_init);
EXPORT_SYMBOL(i810_cleanup);
#define I810_NAME "i810"
-#define I810_DESC "Matrox g200/g400"
+#define I810_DESC "Intel I810"
#define I810_DATE "19991213"
#define I810_MAJOR 0
#define I810_MINOR 0
@@ -54,6 +57,7 @@ static struct file_operations i810_fops = {
mmap: drm_mmap,
read: drm_read,
fasync: drm_fasync,
+ poll: drm_poll,
};
static struct miscdevice i810_misc = {
@@ -80,13 +84,13 @@ static drm_ioctl_desc_t i810_ioctls[] = {
[DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)] = { i810_mapbufs, 1, 0 },
[DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = { i810_freebufs, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { drm_addctx, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { drm_rmctx, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { drm_modctx, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = { drm_getctx, 1, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { drm_switchctx, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = { drm_newctx, 1, 1 },
- [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = { drm_resctx, 1, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { i810_addctx, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { i810_rmctx, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { i810_modctx, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = { i810_getctx, 1, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { i810_switchctx, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = { i810_newctx, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = { i810_resctx, 1, 0 },
[DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)] = { drm_adddraw, 1, 1 },
[DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)] = { drm_rmdraw, 1, 1 },
@@ -104,6 +108,11 @@ static drm_ioctl_desc_t i810_ioctls[] = {
[DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)] = { drm_agp_free, 1, 1 },
[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_I810_INIT)] = { i810_dma_init, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_I810_VERTEX)] = { i810_dma_vertex, 1, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_I810_DMA)] = { i810_dma_general,1, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_I810_FLUSH)] = { i810_flush_ioctl,1, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_I810_GETAGE)] = { i810_getage, 1, 0 },
};
#define I810_IOCTL_COUNT DRM_ARRAY_SIZE(i810_ioctls)
@@ -121,7 +130,7 @@ MODULE_PARM(i810, "s");
int init_module(void)
{
- printk("doing i810_init()\n");
+ DRM_DEBUG("doing i810_init()\n");
return i810_init();
}
@@ -364,7 +373,7 @@ int i810_init(void)
#ifdef MODULE
drm_parse_options(i810);
#endif
- printk("doing misc_register\n");
+ DRM_DEBUG("doing misc_register\n");
if ((retcode = misc_register(&i810_misc))) {
DRM_ERROR("Cannot register \"%s\"\n", I810_NAME);
return retcode;
@@ -372,13 +381,22 @@ int i810_init(void)
dev->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 +404,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 +431,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 +497,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 +637,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 0f5f42bb..d3dc6906 100644
--- a/linux/i810_drv.h
+++ b/linux/i810_drv.h
@@ -31,6 +31,32 @@
#ifndef _I810_DRV_H_
#define _I810_DRV_H_
+#include "i810_drm_public.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);
@@ -54,8 +80,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 +103,25 @@ 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);
+
+
#endif
diff --git a/linux/memory.c b/linux/memory.c
index a8a81abd..559ac739 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 34f1112a..89e4090d 100644
--- a/linux/mga_bufs.c
+++ b/linux/mga_bufs.c
@@ -76,7 +76,7 @@ int mga_addbufs_agp(struct inode *inode, struct file *filp, unsigned int cmd,
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("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);
@@ -121,7 +121,7 @@ int mga_addbufs_agp(struct inode *inode, struct file *filp, unsigned int cmd,
buf->order = order;
buf->used = 0;
- DRM_DEBUG("offset : %d\n", offset);
+ DRM_DEBUG("offset : %ld\n", offset);
buf->offset = offset; /* Hrm */
buf->bus_address = dev->agp->base + agp_offset + offset;
@@ -185,7 +185,7 @@ int mga_addbufs_agp(struct inode *inode, struct file *filp, unsigned int cmd,
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("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);
@@ -193,7 +193,7 @@ int mga_addbufs_agp(struct inode *inode, struct file *filp, unsigned int cmd,
dma->flags = _DRM_DMA_USE_AGP;
- DRM_DEBUG("dma->flags : %lx\n", dma->flags);
+ DRM_DEBUG("dma->flags : %x\n", dma->flags);
return 0;
}
@@ -546,7 +546,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,7 +558,7 @@ 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) {
@@ -576,14 +576,17 @@ int mga_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd,
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->handle : %p\n", map->handle);
DRM_DEBUG("map->mtrr : %d\n", map->mtrr);
-
+ down(&current->mm->mmap_sem);
virtual = do_mmap(filp, 0, map->size, PROT_READ|PROT_WRITE,
MAP_SHARED, (unsigned long)map->offset);
+ up(&current->mm->mmap_sem);
} else {
- virtual = do_mmap(filp, 0, dma->byte_count,
- PROT_READ|PROT_WRITE, MAP_SHARED, 0);
+ down(&current->mm->mmap_sem);
+ virtual = do_mmap(filp, 0, dma->byte_count,
+ PROT_READ|PROT_WRITE, MAP_SHARED, 0);
+ up(&current->mm->mmap_sem);
}
if (virtual > -1024UL) {
/* Real error */
diff --git a/linux/mga_context.c b/linux/mga_context.c
index fb0d336f..2459b35b 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 2e24e5b4..70cd98b1 100644
--- a/linux/mga_dma.c
+++ b/linux/mga_dma.c
@@ -24,7 +24,8 @@
* DEALINGS IN THE SOFTWARE.
*
* Authors: Rickard E. (Rik) Faith <faith@precisioninsight.com>
- * Jeff Hartmann <jhartmann@precisioninsight.com>
+ * Jeff Hartmann <jhartmann@precisioninsight.com>
+ * Keith Whitwell <keithw@precisioninsight.com>
*
* $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 $
*
@@ -35,7 +36,6 @@
#include "mga_drv.h"
#include "mgareg_flags.h"
#include "mga_dma.h"
-#include "mga_state.h"
#include <linux/interrupt.h> /* For task queue support */
@@ -48,643 +48,614 @@
#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 */ );
}
+/* These are two age tags that will never be sent to
+ * the hardware */
+#define MGA_BUF_USED 0xffffffff
+#define MGA_BUF_FREE 0
-static int mga_alloc_kernel_queue(drm_device_t *dev)
+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;
+
+ 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;
+ dev_priv->head->next = item;
}
- if(mga_alloc_kernel_queue(dev) != DRM_KERNEL_CONTEXT) {
- mga_dma_cleanup(dev);
- DRM_ERROR("Kernel context queue not present\n");
+ item = dev_priv->head;
+ while(item) {
+ mga_freelist_debug(item);
+ item = item->next;
}
-
- 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;
-
+ DRM_DEBUG("Head\n");
+ mga_freelist_debug(dev_priv->head);
+ DRM_DEBUG("Tail\n");
+ mga_freelist_debug(dev_priv->tail);
- 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);
-
+ return 0;
+}
- 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;
+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);
}
-
-
-
- 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;
- 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 );
+ dev_priv->head = dev_priv->tail = NULL;
+}
- /* Poll for the first buffer to insure that
- * the status register will be correct
- */
- printk("phys_head : %lx\n", phys_head);
+static int __gettimeinmillis(void)
+{
+ int millis;
- MGA_WRITE(MGAREG_DWGSYNC, MGA_SYNC_TAG);
-
- while(MGA_READ(MGAREG_DWGSYNC) != MGA_SYNC_TAG) {
- int i;
- for(i = 0 ; i < 4096; i++) mga_delay();
- }
-
- 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();
- }
+ millis = ((jiffies / HZ) * 1000) + ((jiffies % HZ) * (1000 / HZ));
+ return millis;
+}
+/* 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;
+ int startTime = 0;
+ int curTime = 0;
+ int timeout_millis = 3000;
+ int i;
+
+ while(1) {
+ if(!test_and_set_bit(0, &dev_priv->dispatch_lock)) {
+ break;
+ }
+ curTime = __gettimeinmillis();
+ if (startTime == 0 || curTime < startTime /*wrap case*/) {
+ startTime = curTime;
+ } else if (curTime - startTime > timeout_millis) {
+ 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();
}
+ startTime = 0;
- printk("dma init was successful\n");
- return 0;
+ DRM_DEBUG("quiescent status : %x\n", MGA_READ(MGAREG_STATUS));
+ while((MGA_READ(MGAREG_STATUS) & 0x00030001) != 0x00020000) {
+ curTime = __gettimeinmillis();
+ if (startTime == 0 || curTime < startTime /*wrap case*/) {
+ startTime = curTime;
+ } else if (curTime - startTime > timeout_millis) {
+ 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)
-
-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) ;
+ dev_priv->sarea_priv->last_enqueue = temp;
- 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);
+ 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_freelist_t *prev;
+ drm_mga_freelist_t *next;
+
+ if((dev_priv->tail->age >> 2) <= FREELIST_COMPARE(status[1])) {
+ drm_mga_buf_priv_t *buf_priv;
+ 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;
+ }
#if 0
- /* For now we need to set this in the ioctl */
- sarea_priv->dirty |= MGASAREA_NEW_CONTEXT;
+ else {
+ mga_freelist_debug(dev_priv->tail);
+ DRM_DEBUG("sarea->last_dispatch %x\n", sarea_priv->last_dispatch);
+ mga_freelist_debug(dev_priv->tail->prev);
+ }
#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);
+ 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 : %lx\n",
+ prim->idx, prim->num_dwords, prim->max_dwords, prim->phys_head);
+ DRM_DEBUG("sec_used : %d swap_pending : %x in_use : %lx 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);
+ drm_mga_prim_buf_t *prim_buffer;
+ int i, temp, size_of_buf;
+ int offset = init->reserved_map_agpstart;
- 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);
-}
-
-/* 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);
- }
+ 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;
}
- 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("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;
+ int startTime = 0;
+ int curTime = 0;
+ int timeout_millis = 3000;
+ int i;
+ int next_idx;
+ PRIMLOCALS;
- atomic_inc(&dev_priv->dispatch_lock);
- if(atomic_read(&dev_priv->dispatch_lock) == 1) {
- /* We got the lock */
- return 1;
+ DRM_DEBUG("mga_fire_primary\n");
+ dev_priv->last_sync_tag = mga_create_sync_tag(dev);
+ dev_priv->last_prim = prim;
+
+ /* 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);
+
+ if(sarea_priv->dirty & MGA_DMA_FLUSH) {
+ DRM_DEBUG("Dma top flush\n");
+ while((MGA_READ(MGAREG_STATUS) & 0x00030001) != 0x00020000) {
+ curTime = __gettimeinmillis();
+ if (startTime == 0 || curTime < startTime /*wrap case*/) {
+ startTime = curTime;
+ } else if (curTime - startTime > timeout_millis) {
+ 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) {
+ curTime = __gettimeinmillis();
+ if (startTime == 0 || curTime < startTime /*wrap case*/) {
+ startTime = curTime;
+ } else if (curTime - startTime > timeout_millis) {
+ 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);
+ DRM_DEBUG("Primarys at fire\n");
+ 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];
+
+/* mga_print_all_primary(dev); */
+ return;
+
+out_prim_wait:
+ {
+ prim->num_dwords = 0;
+ prim->sec_used = 0;
+ clear_bit(0, &prim->in_use);
+ 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;
-
- 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;
+ drm_device_dma_t *dma = dev->dma;
+
+ if(atomic_read(&dev_priv->next_prim->force_fire) ||
+ (atomic_read(&dev_priv->in_flush) && dev_priv->next_prim->num_dwords)) {
+ atomic_inc(&dma->total_prio);
+ return 1;
+ }
+ 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;
+ }
+ }
+ 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 (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 / 2)) {
+ if(dev_priv->next_prim->sec_used >= (MGA_DMA_BUF_NR / 4)) {
+ atomic_inc(&dma->total_missed_free);
+ return 1;
+ }
}
- clear_bit(0, &dev->dma_flag);
-
- /* Dispatch new buffer */
- queue_task(&dev->tq, &tq_immediate);
- mark_bh(IMMEDIATE_BH);
+ 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,
+ 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;
+ 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 +663,247 @@ 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);
+ 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;
+ drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private;
+
mga_dma_schedule(dev, 0);
+ wake_up_interruptible(&dev_priv->wait_queue);
}
-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(mgaWarpIndex) * MGA_MAX_WARP_PIPES);
+
+ for (i = 0 ; i < MGA_MAX_WARP_PIPES ; i++)
+ DRM_DEBUG("warp pipe %d: installed: %d phys_addr: %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 +920,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 +930,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 +946,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 +962,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 +988,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 ||
+ dev_priv->next_prim->num_dwords == 0) break;
+ atomic_inc(&dev->total_sleeps);
+ DRM_DEBUG("Schedule in flush_queue\n");
+ schedule_timeout(HZ/60);
+ 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 +1062,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 +1093,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 +1106,48 @@ 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_device_dma_t *dma = dev->dma;
+ 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(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
index 7f1c5795..97d83005 100644
--- a/linux/mga_dma.h
+++ b/linux/mga_dma.h
@@ -2,30 +2,24 @@
#define MGA_DMA_H
#include "mga_drm_public.h"
+typedef enum {
+ TT_GENERAL,
+ TT_BLIT,
+ TT_VECTOR,
+ TT_VERTEX
+} transferType_t;
-
-/* 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_freelist_t *my_freelist;
} drm_mga_buf_priv_t;
-
-#define MGA_DMA_GENERAL 0
+#define MGA_DMA_GENERAL 0 /* not used */
#define MGA_DMA_VERTEX 1
#define MGA_DMA_SETUP 2
#define MGA_DMA_ILOAD 3
-
+#define MGA_DMA_CLEAR 4 /* placeholder */
+#define MGA_DMA_SWAP 5 /* placeholder */
+#define MGA_DMA_DISCARD 6
#define DWGREG0 0x1c00
#define DWGREG0_END 0x1dff
@@ -37,76 +31,102 @@ typedef struct {
#define ADRINDEX1(r) (u8)(((r - DWGREG1) >> 2) | 0x80)
#define ADRINDEX(r) (ISREG0(r) ? ADRINDEX0(r) : ADRINDEX1(r))
+#define MGA_VERBOSE 0
-/* Macros for inserting commands into a secondary dma buffer.
+#define MGA_NUM_PRIM_BUFS 8
+/* Primary buffer versions of above -- pretty similar really.
*/
-#define DMALOCALS u8 tempIndex[4]; u32 *dma_ptr; \
- int outcount, num_dwords;
+#define PRIMLOCALS u8 tempIndex[4]; u32 *dma_ptr; u32 phys_head; \
+ int outcount, num_dwords
-#define DMAGETPTR(buf) do { \
- dma_ptr = (u32 *)((u8 *)buf->address + buf->used); \
- outcount = 0; \
- num_dwords = buf->used / 4; \
+#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 DMAADVANCE(buf) do { \
- buf->used = num_dwords * 4; \
+#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 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
-
+#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)
-/* Primary buffer versions of above -- pretty similar really.
- */
-#define PRIMLOCALS u8 tempIndex[4]; u32 *dma_ptr; u32 phys_head; \
- int outcount, num_dwords
+#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 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; \
+#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 PRIMADVANCE(dev_priv) do { \
- dev_priv->prim_num_dwords = num_dwords; \
- dev_priv->current_dma_ptr = dma_ptr; \
+#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; \
} \
- 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)
+#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_drm_public.h b/linux/mga_drm_public.h
index 8b21df11..0e91656c 100644
--- a/linux/mga_drm_public.h
+++ b/linux/mga_drm_public.h
@@ -54,11 +54,9 @@
#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
@@ -82,22 +80,18 @@ typedef struct drm_mga_init {
int sarea_priv_offset;
int primary_size;
int warp_ucode_size;
- int fbOffset;
+ int frontOffset;
int backOffset;
int depthOffset;
int textureOffset;
int textureSize;
+ int agpTextureOffset;
+ int agpTextureSize;
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;
@@ -108,12 +102,12 @@ typedef struct _xf86drmClipRectRec {
unsigned short y2;
} xf86drmClipRectRec;
-#define MGA_CLEAR_FRONT 0x1
-#define MGA_CLEAR_BACK 0x2
-#define MGA_CLEAR_DEPTH 0x4
+#define MGA_FRONT 0x1
+#define MGA_BACK 0x2
+#define MGA_DEPTH 0x4
-/* Each context has a state:
+/* 3d state excluding texture units:
*/
#define MGA_CTXREG_DSTORG 0 /* validated */
#define MGA_CTXREG_MACCESS 1
@@ -124,7 +118,8 @@ typedef struct _xf86drmClipRectRec {
#define MGA_CTXREG_WFLAG 6
#define MGA_CTXREG_TDUAL0 7
#define MGA_CTXREG_TDUAL1 8
-#define MGA_CTX_SETUP_SIZE 9
+#define MGA_CTXREG_FCOL 9
+#define MGA_CTX_SETUP_SIZE 10
/* 2d state
*/
@@ -146,33 +141,59 @@ typedef struct _xf86drmClipRectRec {
#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
+#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<<MGA_DMA_BUF_ORDER)
+#define MGA_DMA_BUF_NR 63
-/* Keep this small for testing
+/* Keep these small for testing.
*/
-#define MGA_NR_SAREA_CLIPRECTS 2
+#define MGA_NR_SAREA_CLIPRECTS 8
+
+
-/* Upto 128 regions. Minimum region size of 256k.
+/* 2 heaps (1 for card, 1 for agp), each divided into upto 128
+ * regions, subject to a minimum region size of (1<<16) == 64k.
+ *
+ * Clients may subdivide regions internally, but when sharing between
+ * clients, the region size is the minimum granularity.
*/
-#define MGA_NR_TEX_REGIONS 128
-#define MGA_MIN_LOG_TEX_GRANULARITY 18
+#define MGA_CARD_HEAP 0
+#define MGA_AGP_HEAP 1
+#define MGA_NR_TEX_HEAPS 2
+#define MGA_NR_TEX_REGIONS 16
+#define MGA_LOG_MIN_TEX_REGION_SIZE 16
typedef struct {
- unsigned char next, prev;
- unsigned char in_use;
- int age;
+ unsigned char next, prev;
+ unsigned char in_use;
+ int age;
} mgaTexRegion;
+
+
typedef struct
{
+ /* The channel for communication of state information to the kernel
+ * on firing a vertex dma buffer.
+ */
unsigned int ContextState[MGA_CTX_SETUP_SIZE];
unsigned int ServerState[MGA_2D_SETUP_SIZE];
unsigned int TexState[2][MGA_TEX_SETUP_SIZE];
@@ -182,37 +203,88 @@ typedef struct
unsigned int nbox;
xf86drmClipRectRec boxes[MGA_NR_SAREA_CLIPRECTS];
- /* kernel doesn't touch from here down */
+
+ /* Information about the most recently used 3d drawable. The
+ * client fills in the req_* fields, the server fills in the
+ * exported_ fields and puts the cliprects into boxes, above.
+ *
+ * The client clears the exported_drawable field before
+ * clobbering the boxes data.
+ */
+ unsigned int req_drawable; /* the X drawable id */
+ unsigned int req_draw_buffer; /* MGA_FRONT or MGA_BACK */
+
+ unsigned int exported_drawable;
+ unsigned int exported_index;
+ unsigned int exported_stamp;
+ unsigned int exported_buffers;
+ unsigned int exported_nfront;
+ unsigned int exported_nback;
+ int exported_back_x, exported_front_x, exported_w;
+ int exported_back_y, exported_front_y, exported_h;
+ xf86drmClipRectRec exported_boxes[MGA_NR_SAREA_CLIPRECTS];
+
+ /* Counters for aging textures and for client-side throttling.
+ */
+ int last_enqueue; /* last time a buffer was enqueued */
+ int last_dispatch; /* age of the most recently dispatched buffer */
+ int last_quiescent; /* */
+
+
+ /* LRU lists for texture memory in agp space and on the card
+ */
+ mgaTexRegion texList[MGA_NR_TEX_HEAPS][MGA_NR_TEX_REGIONS+1];
+ unsigned int texAge[MGA_NR_TEX_HEAPS];
+
+ /* Mechanism to validate card state.
+ */
int ctxOwner;
- mgaTexRegion texList[MGA_NR_TEX_REGIONS+1];
- int texAge;
+
+
} drm_mga_sarea_t;
/* Device specific ioctls:
*/
typedef struct {
+ int idx;
int clear_color;
int clear_depth;
int flags;
} drm_mga_clear_t;
-
typedef struct {
- int flags; /* not actually used? */
+ int idx;
} drm_mga_swap_t;
typedef struct {
unsigned int destOrg;
- unsigned int mAccess;
- unsigned int pitch;
- xf86drmClipRectRec texture;
- int idx;
+ int idx;
+ int length;
} drm_mga_iload_t;
+/* These may be placeholders if we have more cliprects than
+ * MGA_NR_SAREA_CLIPRECTS. In that case, idx != real_idx; idx is
+ * the number of a bogus buffer, real_idx is the real buffer to be
+ * rendered multiple times.
+ *
+ * This is a hack to work around assumptions built into the drm, and
+ * may shortly be removed.
+ */
+typedef struct {
+ int idx; /* buffer to queue and free on completion */
+ int real_idx; /* buffer to execute */
+ int real_used; /* buf->used in for real buffer */
+ int discard; /* */
+} drm_mga_vertex_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)
+#define DRM_IOCTL_MGA_VERTEX DRM_IOW( 0x44, drm_mga_vertex_t)
+#define DRM_IOCTL_MGA_FLUSH DRM_IOW( 0x45, drm_lock_t )
+
#endif
diff --git a/linux/mga_drv.c b/linux/mga_drv.c
index 8bc25617..48041354 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 bc7808b0..60c00f93 100644
--- a/linux/mga_drv.h
+++ b/linux/mga_drv.h
@@ -24,7 +24,7 @@
* DEALINGS IN THE SOFTWARE.
*
* Authors: Rickard E. (Rik) Faith <faith@precisioninsight.com>
- * Jeff Hartmann <jhartmann@precisioninsight.com>
+ * Jeff Hartmann <jhartmann@precisioninsight.com>
*
* $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 $
*/
@@ -33,6 +33,27 @@
#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;
int buffer_map_idx;
@@ -40,7 +61,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;
@@ -50,24 +71,31 @@ typedef struct _drm_mga_private {
int sgram;
int use_agp;
mgaWarpIndex 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 +120,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 +154,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);
diff --git a/linux/mga_state.c b/linux/mga_state.c
index d09881ba..941ca4d0 100644
--- a/linux/mga_state.c
+++ b/linux/mga_state.c
@@ -24,7 +24,7 @@
* DEALINGS IN THE SOFTWARE.
*
* Authors: Jeff Hartmann <jhartmann@precisioninsight.com>
- * Keith Whitwell <keithw@precisioninsight.com>
+ * Keith Whitwell <keithw@precisioninsight.com>
*
* $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 $
*
@@ -35,180 +35,209 @@
#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, xf86drmClipRectRec *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 +256,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 +285,640 @@ 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;
+
+/* DRM_DEBUG("BUF PIPE: %x LOADED PIPE: %x\n", */
+/* sarea_priv->WarpPipe, dev_priv->WarpPipe); */
+
+ 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;
+ }
+ }
}
+/* WARNING if you change any of the state functions
+ * verify these numbers */
+static int mgaCalcState( drm_mga_private_t *dev_priv )
+{
+ /* It doesn't hurt to overestimate.
+ */
+ return 25+15+30+25;
+}
/* 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 inline 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 inline void mga_dma_dispatch_vertex(drm_device_t *dev,
+ drm_buf_t *buf, int real_idx,
+ int idx)
+{
+ 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(real_idx == idx) {
+ buf_priv->my_freelist->age = dev_priv->last_sync_tag;
+ mga_freelist_put(dev, buf);
+ }
+
+ /* 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 );
+ 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 );
+}
+
+/* Not currently used
+ */
+static inline void mga_dma_dispatch_general(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;
+ unsigned long address = (unsigned long)buf->bus_address;
+ int length = buf->used;
+ int use_agp = PDEA_pagpxfer_enable;
+ PRIMLOCALS;
+
+ PRIM_OVERFLOW(dev, dev_priv, 10);
+ PRIMGETPTR(dev_priv);
+
+ dev_priv->last_sync_tag = mga_create_sync_tag(dev);
+ buf_priv->my_freelist->age = dev_priv->last_sync_tag;
+ mga_freelist_put(dev, buf);
+
+ PRIMOUTREG( MGAREG_DMAPAD, 0);
+ PRIMOUTREG( MGAREG_DMAPAD, 0);
+ PRIMOUTREG( MGAREG_SECADDRESS, ((__u32)address) | TT_GENERAL);
+ PRIMOUTREG( MGAREG_SECEND, (((__u32)(address + length)) | use_agp));
+ PRIMOUTREG( MGAREG_DMAPAD, 0);
+ PRIMOUTREG( MGAREG_DMAPAD, 0);
+ PRIMOUTREG( MGAREG_DMAPAD, 0);
+ PRIMOUTREG( MGAREG_DWGSYNC, dev_priv->last_sync_tag);
+ PRIMADVANCE(dev_priv);
+}
+
+static inline 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;
+ xf86drmClipRectRec *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 inline 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;
+ xf86drmClipRectRec *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 (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 (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);
+
+ 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;
+ 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);
+
+
+ DRM_DEBUG("mga_vertex\n");
+ buf = dma->buflist[ vertex.real_idx ];
+ buf_priv = buf->dev_private;
+
+ if (!mgaVerifyState(dev_priv)) {
+ if(vertex.real_idx == vertex.idx) {
+ buf_priv->my_freelist->age = dev_priv->last_sync_tag;
+ mga_freelist_put(dev, buf);
+ }
+ return -EINVAL;
+ }
+
+ buf->used = vertex.real_used;
+ if(vertex.discard) {
+ buf_priv->my_freelist->age = dev_priv->last_sync_tag;
+ mga_freelist_put(dev, buf);
+ } else {
+ mga_dma_dispatch_vertex(dev, buf, vertex.real_idx,
+ vertex.idx);
+ }
+ 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);
+
+ /* 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
index e7b952e0..40fa1451 100644
--- a/linux/mga_state.h
+++ b/linux/mga_state.h
@@ -3,9 +3,6 @@
#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 );
diff --git a/linux/picker.c b/linux/picker.c
index ecdb2c15..0bd8bfd5 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 54aba58c..db98fd6a 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/r128_context.c b/linux/r128_context.c
new file mode 100644
index 00000000..d146035a
--- /dev/null
+++ b/linux/r128_context.c
@@ -0,0 +1,212 @@
+/* r128_context.c -- IOCTLs for r128 contexts -*- linux-c -*-
+ * Created: Mon Dec 13 09:51:35 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999, 2000 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 <faith@precisioninsight.com>
+ *
+ * $XFree86$
+ *
+ */
+
+#include <linux/sched.h>
+
+#define __NO_VERSION__
+#include "drmP.h"
+#include "r128_drv.h"
+
+extern drm_ctx_t r128_res_ctx;
+
+static int r128_alloc_queue(drm_device_t *dev)
+{
+ static int context = 0;
+
+ return drm_ctxbitmap_next(dev);
+}
+
+int r128_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) {
+ r128_context_switch_complete(dev, new);
+ } else {
+ sprintf(buf, "C %d %d\n", old, new);
+ drm_write_string(dev, buf);
+ }
+
+ return 0;
+}
+
+int r128_context_switch_complete(drm_device_t *dev, int new)
+{
+ dev->last_context = new; /* PRE/POST: This is the _only_ writer. */
+ dev->last_switch = jiffies;
+
+ if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+ DRM_ERROR("Lock isn't held after context switch\n");
+ }
+
+ /* 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 r128_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 r128_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 = r128_alloc_queue(dev)) == DRM_KERNEL_CONTEXT) {
+ /* Skip kernel's context and get a new one. */
+ ctx.handle = r128_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;
+}
+
+int r128_modctx(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);
+ if (ctx.flags==_DRM_CONTEXT_PRESERVED)
+ r128_res_ctx.handle=ctx.handle;
+ return 0;
+}
+
+int r128_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 r128_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 r128_context_switch(dev, dev->last_context, ctx.handle);
+}
+
+int r128_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);
+ r128_context_switch_complete(dev, ctx.handle);
+
+ return 0;
+}
+
+int r128_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);
+ drm_ctxbitmap_free(dev, ctx.handle);
+
+ return 0;
+}
diff --git a/linux/r128_drv.c b/linux/r128_drv.c
new file mode 100644
index 00000000..d477a70d
--- /dev/null
+++ b/linux/r128_drv.c
@@ -0,0 +1,712 @@
+/* r128_drv.c -- ATI Rage 128 driver -*- linux-c -*-
+ * Created: Mon Dec 13 09:47:27 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999, 2000 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 <faith@precisioninsight.com>
+ *
+ * $XFree86$
+ *
+ */
+
+#define EXPORT_SYMTAB
+#include "drmP.h"
+#include "r128_drv.h"
+EXPORT_SYMBOL(r128_init);
+EXPORT_SYMBOL(r128_cleanup);
+
+#define R128_NAME "r128"
+#define R128_DESC "r128"
+#define R128_DATE "19991213"
+#define R128_MAJOR 0
+#define R128_MINOR 0
+#define R128_PATCHLEVEL 1
+
+static drm_device_t r128_device;
+drm_ctx_t r128_res_ctx;
+
+static struct file_operations r128_fops = {
+ open: r128_open,
+ flush: drm_flush,
+ release: r128_release,
+ ioctl: r128_ioctl,
+ mmap: drm_mmap,
+ read: drm_read,
+ fasync: drm_fasync,
+ poll: drm_poll,
+};
+
+static struct miscdevice r128_misc = {
+ minor: MISC_DYNAMIC_MINOR,
+ name: R128_NAME,
+ fops: &r128_fops,
+};
+
+static drm_ioctl_desc_t r128_ioctls[] = {
+ [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = { r128_version, 0, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = { drm_getunique, 0, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)] = { drm_getmagic, 0, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = { drm_irq_busid, 0, 1 },
+
+ [DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)] = { drm_setunique, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_BLOCK)] = { drm_block, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)] = { drm_unblock, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)] = { drm_authmagic, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)] = { drm_addmap, 1, 1 },
+
+ [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { r128_addctx, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { r128_rmctx, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { r128_modctx, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = { r128_getctx, 1, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { r128_switchctx, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = { r128_newctx, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = { r128_resctx, 1, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)] = { drm_adddraw, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)] = { drm_rmdraw, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_LOCK)] = { r128_lock, 1, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = { r128_unlock, 1, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { drm_finish, 1, 0 },
+
+ [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, 0 },
+ [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_bind, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = { drm_agp_unbind, 1, 1 },
+};
+#define R128_IOCTL_COUNT DRM_ARRAY_SIZE(r128_ioctls)
+
+#ifdef MODULE
+int init_module(void);
+void cleanup_module(void);
+static char *r128 = NULL;
+
+MODULE_AUTHOR("Precision Insight, Inc., Cedar Park, Texas.");
+MODULE_DESCRIPTION("r128");
+MODULE_PARM(r128, "s");
+
+/* init_module is called when insmod is used to load the module */
+
+int init_module(void)
+{
+ return r128_init();
+}
+
+/* cleanup_module is called when rmmod is used to unload the module */
+
+void cleanup_module(void)
+{
+ r128_cleanup();
+}
+#endif
+
+#ifndef MODULE
+/* r128_setup is called by the kernel to parse command-line options passed
+ * via the boot-loader (e.g., LILO). It calls the insmod option routine,
+ * drm_parse_drm.
+ *
+ * This is not currently supported, since it requires changes to
+ * linux/init/main.c. */
+
+
+void __init r128_setup(char *str, int *ints)
+{
+ if (ints[0] != 0) {
+ DRM_ERROR("Illegal command line format, ignored\n");
+ return;
+ }
+ drm_parse_options(str);
+}
+#endif
+
+static int r128_setup(drm_device_t *dev)
+{
+ int i;
+
+ atomic_set(&dev->ioctl_count, 0);
+ atomic_set(&dev->vma_count, 0);
+ dev->buf_use = 0;
+ atomic_set(&dev->buf_alloc, 0);
+
+ atomic_set(&dev->total_open, 0);
+ atomic_set(&dev->total_close, 0);
+ atomic_set(&dev->total_ioctl, 0);
+ atomic_set(&dev->total_irq, 0);
+ atomic_set(&dev->total_ctx, 0);
+ atomic_set(&dev->total_locks, 0);
+ atomic_set(&dev->total_unlocks, 0);
+ atomic_set(&dev->total_contends, 0);
+ atomic_set(&dev->total_sleeps, 0);
+
+ for (i = 0; i < DRM_HASH_SIZE; i++) {
+ dev->magiclist[i].head = NULL;
+ dev->magiclist[i].tail = NULL;
+ }
+ dev->maplist = NULL;
+ dev->map_count = 0;
+ dev->vmalist = NULL;
+ dev->lock.hw_lock = NULL;
+ init_waitqueue_head(&dev->lock.lock_queue);
+ dev->queue_count = 0;
+ dev->queue_reserved = 0;
+ dev->queue_slots = 0;
+ dev->queuelist = NULL;
+ dev->irq = 0;
+ dev->context_flag = 0;
+ dev->interrupt_flag = 0;
+ dev->dma = 0;
+ dev->dma_flag = 0;
+ dev->last_context = 0;
+ dev->last_switch = 0;
+ dev->last_checked = 0;
+ init_timer(&dev->timer);
+ init_waitqueue_head(&dev->context_wait);
+
+ dev->ctx_start = 0;
+ dev->lck_start = 0;
+
+ dev->buf_rp = dev->buf;
+ dev->buf_wp = dev->buf;
+ dev->buf_end = dev->buf + DRM_BSZ;
+ dev->buf_async = NULL;
+ init_waitqueue_head(&dev->buf_readers);
+ init_waitqueue_head(&dev->buf_writers);
+
+ r128_res_ctx.handle=-1;
+
+ DRM_DEBUG("\n");
+
+ /* The kernel's context could be created here, but is now created
+ in drm_dma_enqueue. This is more resource-efficient for
+ hardware that does not do DMA, but may mean that
+ drm_select_queue fails between the time the interrupt is
+ initialized and the time the queues are initialized. */
+
+ return 0;
+}
+
+
+static int r128_takedown(drm_device_t *dev)
+{
+ int i;
+ drm_magic_entry_t *pt, *next;
+ drm_map_t *map;
+ drm_vma_entry_t *vma, *vma_next;
+
+ DRM_DEBUG("\n");
+
+ down(&dev->struct_sem);
+ del_timer(&dev->timer);
+
+ if (dev->devname) {
+ drm_free(dev->devname, strlen(dev->devname)+1, DRM_MEM_DRIVER);
+ dev->devname = NULL;
+ }
+
+ if (dev->unique) {
+ drm_free(dev->unique, strlen(dev->unique)+1, DRM_MEM_DRIVER);
+ dev->unique = NULL;
+ dev->unique_len = 0;
+ }
+ /* Clear pid list */
+ for (i = 0; i < DRM_HASH_SIZE; i++) {
+ for (pt = dev->magiclist[i].head; pt; pt = next) {
+ next = pt->next;
+ drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
+ }
+ dev->magiclist[i].head = dev->magiclist[i].tail = NULL;
+ }
+
+ /* Clear AGP information */
+ if (dev->agp) {
+ drm_agp_mem_t *entry;
+ drm_agp_mem_t *nexte;
+
+ /* Remove AGP resources, but leave dev->agp
+ intact until r128_cleanup is called. */
+ for (entry = dev->agp->memory; entry; entry = nexte) {
+ nexte = entry->next;
+ if (entry->bound) drm_unbind_agp(entry->memory);
+ drm_free_agp(entry->memory, entry->pages);
+ drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
+ }
+ dev->agp->memory = NULL;
+
+ if (dev->agp->acquired && drm_agp.release)
+ (*drm_agp.release)();
+
+ dev->agp->acquired = 0;
+ dev->agp->enabled = 0;
+ }
+
+ /* Clear vma list (only built for debugging) */
+ if (dev->vmalist) {
+ for (vma = dev->vmalist; vma; vma = vma_next) {
+ vma_next = vma->next;
+ drm_free(vma, sizeof(*vma), DRM_MEM_VMAS);
+ }
+ dev->vmalist = NULL;
+ }
+
+ /* Clear map area and mtrr information */
+ if (dev->maplist) {
+ for (i = 0; i < dev->map_count; i++) {
+ map = dev->maplist[i];
+ switch (map->type) {
+ case _DRM_REGISTERS:
+ case _DRM_FRAME_BUFFER:
+#ifdef CONFIG_MTRR
+ if (map->mtrr >= 0) {
+ int retcode;
+ retcode = mtrr_del(map->mtrr,
+ map->offset,
+ map->size);
+ DRM_DEBUG("mtrr_del = %d\n", retcode);
+ }
+#endif
+ drm_ioremapfree(map->handle, map->size);
+ break;
+ case _DRM_SHM:
+ drm_free_pages((unsigned long)map->handle,
+ drm_order(map->size)
+ - 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);
+ }
+ drm_free(dev->maplist,
+ dev->map_count * sizeof(*dev->maplist),
+ DRM_MEM_MAPS);
+ dev->maplist = NULL;
+ dev->map_count = 0;
+ }
+
+ if (dev->lock.hw_lock) {
+ dev->lock.hw_lock = NULL; /* SHM removed */
+ dev->lock.pid = 0;
+ wake_up_interruptible(&dev->lock.lock_queue);
+ }
+ up(&dev->struct_sem);
+
+ return 0;
+}
+
+/* r128_init is called via init_module at module load time, or via
+ * linux/init/main.c (this is not currently supported). */
+
+int r128_init(void)
+{
+ int retcode;
+ drm_device_t *dev = &r128_device;
+
+ DRM_DEBUG("\n");
+
+ memset((void *)dev, 0, sizeof(*dev));
+ dev->count_lock = SPIN_LOCK_UNLOCKED;
+ sema_init(&dev->struct_sem, 1);
+
+#ifdef MODULE
+ drm_parse_options(r128);
+#endif
+
+ if ((retcode = misc_register(&r128_misc))) {
+ DRM_ERROR("Cannot register \"%s\"\n", R128_NAME);
+ return retcode;
+ }
+ dev->device = MKDEV(MISC_MAJOR, r128_misc.minor);
+ dev->name = R128_NAME;
+
+ drm_mem_init();
+ drm_proc_init(dev);
+
+ dev->agp = drm_agp_init();
+
+#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
+
+ if((retcode = drm_ctxbitmap_init(dev))) {
+ DRM_ERROR("Cannot allocate memory for context bitmap.\n");
+ drm_proc_cleanup();
+ misc_deregister(&r128_misc);
+ r128_takedown(dev);
+ return retcode;
+ }
+
+ DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
+ R128_NAME,
+ R128_MAJOR,
+ R128_MINOR,
+ R128_PATCHLEVEL,
+ R128_DATE,
+ r128_misc.minor);
+
+ return 0;
+}
+
+/* r128_cleanup is called via cleanup_module at module unload time. */
+
+void r128_cleanup(void)
+{
+ drm_device_t *dev = &r128_device;
+
+ DRM_DEBUG("\n");
+
+ drm_proc_cleanup();
+ if (misc_deregister(&r128_misc)) {
+ DRM_ERROR("Cannot unload module\n");
+ } else {
+ DRM_INFO("Module unloaded\n");
+ }
+ drm_ctxbitmap_cleanup(dev);
+ r128_takedown(dev);
+ if (dev->agp) {
+ /* FIXME -- free other information, too */
+ drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS);
+ dev->agp = NULL;
+ }
+}
+
+int r128_version(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_version_t version;
+ int len;
+
+ copy_from_user_ret(&version,
+ (drm_version_t *)arg,
+ sizeof(version),
+ -EFAULT);
+
+#define DRM_COPY(name,value) \
+ len = strlen(value); \
+ if (len > name##_len) len = name##_len; \
+ name##_len = strlen(value); \
+ if (len && name) { \
+ copy_to_user_ret(name, value, len, -EFAULT); \
+ }
+
+ version.version_major = R128_MAJOR;
+ version.version_minor = R128_MINOR;
+ version.version_patchlevel = R128_PATCHLEVEL;
+
+ DRM_COPY(version.name, R128_NAME);
+ DRM_COPY(version.date, R128_DATE);
+ DRM_COPY(version.desc, R128_DESC);
+
+ copy_to_user_ret((drm_version_t *)arg,
+ &version,
+ sizeof(version),
+ -EFAULT);
+ return 0;
+}
+
+int r128_open(struct inode *inode, struct file *filp)
+{
+ drm_device_t *dev = &r128_device;
+ int retcode = 0;
+
+ DRM_DEBUG("open_count = %d\n", dev->open_count);
+ if (!(retcode = drm_open_helper(inode, filp, dev))) {
+ MOD_INC_USE_COUNT;
+ atomic_inc(&dev->total_open);
+ spin_lock(&dev->count_lock);
+ if (!dev->open_count++) {
+ spin_unlock(&dev->count_lock);
+ return r128_setup(dev);
+ }
+ spin_unlock(&dev->count_lock);
+ }
+ return retcode;
+}
+
+int r128_release(struct inode *inode, struct file *filp)
+{
+ drm_file_t *priv = filp->private_data;
+ 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;
+ }
+ spin_unlock(&dev->count_lock);
+ return r128_takedown(dev);
+ }
+ spin_unlock(&dev->count_lock);
+ }
+ return retcode;
+}
+
+/* r128_ioctl is called whenever a process performs an ioctl on /dev/drm. */
+
+int r128_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ int nr = DRM_IOCTL_NR(cmd);
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ int retcode = 0;
+ drm_ioctl_desc_t *ioctl;
+ drm_ioctl_t *func;
+
+ atomic_inc(&dev->ioctl_count);
+ atomic_inc(&dev->total_ioctl);
+ ++priv->ioctl_count;
+
+ DRM_DEBUG("pid = %d, cmd = 0x%02x, nr = 0x%02x, dev 0x%x, auth = %d\n",
+ current->pid, cmd, nr, dev->device, priv->authenticated);
+
+ if (nr >= R128_IOCTL_COUNT) {
+ retcode = -EINVAL;
+ } else {
+ ioctl = &r128_ioctls[nr];
+ func = ioctl->func;
+
+ if (!func) {
+ DRM_DEBUG("no function\n");
+ retcode = -EINVAL;
+ } else if ((ioctl->root_only && !capable(CAP_SYS_ADMIN))
+ || (ioctl->auth_needed && !priv->authenticated)) {
+ retcode = -EACCES;
+ } else {
+ retcode = (func)(inode, filp, cmd, arg);
+ }
+ }
+
+ atomic_dec(&dev->ioctl_count);
+ return retcode;
+}
+
+int r128_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;
+#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);
+
+ if (lock.context == DRM_KERNEL_CONTEXT) {
+ DRM_ERROR("Process %d using kernel context %d\n",
+ 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 0
+ /* dev->queue_count == 0 right now for
+ r128. FIXME? */
+ if (lock.context < 0 || lock.context >= dev->queue_count)
+ return -EINVAL;
+#endif
+
+ if (!ret) {
+#if 0
+ if (_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)
+ != lock.context) {
+ long j = jiffies - dev->lock.lock_time;
+
+ if (lock.context == r128_res_ctx.handle &&
+ j >= 0 && j < DRM_LOCK_SLICE) {
+ /* Can't take lock if we just had it and
+ there is contention. */
+ DRM_DEBUG("%d (pid %d) delayed j=%d dev=%d jiffies=%d\n",
+ lock.context, current->pid, j,
+ dev->lock.lock_time, jiffies);
+ current->state = TASK_INTERRUPTIBLE;
+ current->policy |= SCHED_YIELD;
+ schedule_timeout(DRM_LOCK_SLICE-j);
+ DRM_DEBUG("jiffies=%d\n", jiffies);
+ }
+ }
+#endif
+ add_wait_queue(&dev->lock.lock_queue, &entry);
+ for (;;) {
+ if (!dev->lock.hw_lock) {
+ /* Device has been unregistered */
+ ret = -EINTR;
+ break;
+ }
+ if (drm_lock_take(&dev->lock.hw_lock->lock,
+ lock.context)) {
+ dev->lock.pid = current->pid;
+ dev->lock.lock_time = jiffies;
+ atomic_inc(&dev->total_locks);
+ break; /* Got lock */
+ }
+
+ /* Contention */
+ atomic_inc(&dev->total_sleeps);
+ current->state = TASK_INTERRUPTIBLE;
+#if 1
+ current->policy |= SCHED_YIELD;
+#endif
+ schedule();
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&dev->lock.lock_queue, &entry);
+ }
+
+#if 0
+ if (!ret && dev->last_context != lock.context &&
+ lock.context != r128_res_ctx.handle &&
+ dev->last_context != r128_res_ctx.handle) {
+ add_wait_queue(&dev->context_wait, &entry);
+ current->state = TASK_INTERRUPTIBLE;
+ /* PRE: dev->last_context != lock.context */
+ r128_context_switch(dev, dev->last_context, lock.context);
+ /* POST: we will wait for the context
+ switch and will dispatch on a later call
+ when dev->last_context == lock.context
+ NOTE WE HOLD THE LOCK THROUGHOUT THIS
+ TIME! */
+ current->policy |= SCHED_YIELD;
+ schedule();
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&dev->context_wait, &entry);
+ if (signal_pending(current)) {
+ ret = -EINTR;
+ } else if (dev->last_context != lock.context) {
+ DRM_ERROR("Context mismatch: %d %d\n",
+ dev->last_context, lock.context);
+ }
+ }
+#endif
+
+ if (!ret) {
+ if (lock.flags & _DRM_LOCK_READY) {
+ /* Wait for space in DMA/FIFO */
+ }
+ if (lock.flags & _DRM_LOCK_QUIESCENT) {
+ /* Make hardware quiescent */
+#if 0
+ r128_quiescent(dev);
+#endif
+ }
+ }
+
+#if 0
+ DRM_ERROR("pid = %5d, old counter = %5ld\n",
+ current->pid, current->counter);
+#endif
+ if (lock.context != r128_res_ctx.handle) {
+ current->counter = 5;
+ current->priority = DEF_PRIORITY/4;
+ }
+#if 0
+ while (current->counter > 25)
+ current->counter >>= 1; /* decrease time slice */
+ DRM_ERROR("pid = %5d, new counter = %5ld\n",
+ current->pid, current->counter);
+#endif
+ DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock");
+
+#if DRM_DMA_HISTOGRAM
+ atomic_inc(&dev->histo.lacq[drm_histogram_slot(get_cycles() - start)]);
+#endif
+
+ return ret;
+}
+
+
+int r128_unlock(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;
+
+ copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT);
+
+ if (lock.context == DRM_KERNEL_CONTEXT) {
+ DRM_ERROR("Process %d using kernel context %d\n",
+ current->pid, lock.context);
+ return -EINVAL;
+ }
+
+ DRM_DEBUG("%d frees lock (%d holds)\n",
+ lock.context,
+ _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+ 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);
+ /* FIXME: Try to send data to card here */
+ if (!dev->context_flag) {
+ if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
+ DRM_KERNEL_CONTEXT)) {
+ DRM_ERROR("\n");
+ }
+ }
+
+#if 0
+ current->policy |= SCHED_YIELD;
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(1000);
+#endif
+
+ if (lock.context != r128_res_ctx.handle) {
+ current->counter = 5;
+ current->priority = DEF_PRIORITY;
+ }
+#if 0
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(10);
+#endif
+
+ return 0;
+}
diff --git a/linux/r128_drv.h b/linux/r128_drv.h
new file mode 100644
index 00000000..c1faf764
--- /dev/null
+++ b/linux/r128_drv.h
@@ -0,0 +1,68 @@
+/* r128_drv.h -- Private header for r128 driver -*- linux-c -*-
+ * Created: Mon Dec 13 09:51:11 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 <faith@precisioninsight.com>
+ *
+ * $XFree86$
+ *
+ */
+
+#ifndef _R128_DRV_H_
+#define _R128_DRV_H_
+
+ /* r128_drv.c */
+extern int r128_init(void);
+extern void r128_cleanup(void);
+extern int r128_version(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int r128_open(struct inode *inode, struct file *filp);
+extern int r128_release(struct inode *inode, struct file *filp);
+extern int r128_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int r128_lock(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int r128_unlock(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+
+ /* r128_context.c */
+
+extern int r128_resctx(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int r128_addctx(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int r128_modctx(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int r128_getctx(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int r128_switchctx(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int r128_newctx(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int r128_rmctx(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+
+extern int r128_context_switch(drm_device_t *dev, int old, int new);
+extern int r128_context_switch_complete(drm_device_t *dev, int new);
+#endif
diff --git a/linux/tdfx_context.c b/linux/tdfx_context.c
index 842d6f5d..74b107bd 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 57c1c719..fb7a997b 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 85470ac5..389f2fae 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 7b8e8826..ebc6f7e7 100644
--- a/shared-core/drm.h
+++ b/shared-core/drm.h
@@ -101,7 +101,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 +166,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 +241,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 +312,14 @@ 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)
+
+/* 0x40 is reserved for mga dma init */
#endif
diff --git a/shared/drm.h b/shared/drm.h
index 7b8e8826..ebc6f7e7 100644
--- a/shared/drm.h
+++ b/shared/drm.h
@@ -101,7 +101,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 +166,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 +241,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 +312,14 @@ 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)
+
+/* 0x40 is reserved for mga dma init */
#endif
diff --git a/tests/drmstat.c b/tests/drmstat.c
index 8fe6f707..a96a38b2 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;
}