summaryrefslogtreecommitdiff
path: root/linux-core
diff options
context:
space:
mode:
authorJeff Hartmann <jhartmann@valinux.com>2000-04-04 22:08:14 +0000
committerJeff Hartmann <jhartmann@valinux.com>2000-04-04 22:08:14 +0000
commitba1b1ae3806490cce16a9c8957b52cd74967f463 (patch)
treeec80e9e61fac3a0f1a0eafaedef239c419a89403 /linux-core
parent7d715d1800031ccbd37db7f88896464c0e838f10 (diff)
Merged mga branch with trunk
Diffstat (limited to 'linux-core')
-rw-r--r--linux-core/Makefile.kernel18
-rw-r--r--linux-core/drmP.h127
-rw-r--r--linux-core/i810_dma.c1228
-rw-r--r--linux-core/i810_drm.h93
-rw-r--r--linux-core/i810_drv.c141
-rw-r--r--linux-core/i810_drv.h132
-rw-r--r--linux-core/mga_drv.c34
-rw-r--r--linux-core/tdfx_drv.c44
8 files changed, 1255 insertions, 562 deletions
diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel
index 44d75c48..2ea6c721 100644
--- a/linux-core/Makefile.kernel
+++ b/linux-core/Makefile.kernel
@@ -14,7 +14,8 @@
L_TARGET := libdrm.a
L_OBJS := init.o memory.o proc.o auth.o context.o drawable.o bufs.o \
- lists.o lock.o ioctl.o fops.o vm.o dma.o
+ lists.o lock.o ioctl.o fops.o vm.o dma.o ctxbitmap.o \
+ agpsupport.o
M_OBJS :=
@@ -26,6 +27,14 @@ ifdef CONFIG_DRM_TDFX
M_OBJS += tdfx.o
endif
+ifdef CONFIG_DRM_MGA
+M_OBJS += mga.o
+endif
+
+ifdef CONFIG_DRM_R128
+M_OBJS += r128.o
+endif
+
include $(TOPDIR)/Rules.make
gamma.o: gamma_drv.o gamma_dma.o $(L_TARGET)
@@ -33,3 +42,10 @@ gamma.o: gamma_drv.o gamma_dma.o $(L_TARGET)
tdfx.o: tdfx_drv.o tdfx_context.o $(L_TARGET)
$(LD) $(LD_RFLAG) -r -o $@ tdfx_drv.o tdfx_context.o -L. -ldrm
+
+i810.o: i810_drv.o i810_context.o $(L_TARGET)
+ $(LD) $(LD_RFLAG) -r -o $@ i810_drv.o i810_bufs.o i810_dma.o i810_context.o -L. -ldrm
+
+mga.o: mga_drv.o mga_context.o mga_dma.o mga_bufs.o $(L_TARGET)
+ $(LD) $(LD_RFLAG) -r -o $@ mga_drv.o mga_bufs.o mga_dma.o mga_context.o mga_state.o -L. -ldrm
+
diff --git a/linux-core/drmP.h b/linux-core/drmP.h
index 312fba36..f8e78eab 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/tqueue.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 * 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..30fda5b8 100644
--- a/linux-core/i810_dma.c
+++ b/linux-core/i810_dma.c
@@ -25,8 +25,9 @@
*
* Authors: Rickard E. (Rik) Faith <faith@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 $
+ * $XFree86$
*
*/
@@ -36,6 +37,9 @@
#include <linux/interrupt.h> /* For task queue support */
+#define I810_BUF_FREE 1
+#define I810_BUF_USED 0
+
#define I810_REG(reg) 2
#define I810_BASE(reg) ((unsigned long) \
dev->maplist[I810_REG(reg)]->handle)
@@ -43,544 +47,457 @@
#define I810_DEREF(reg) *(__volatile__ int *)I810_ADDR(reg)
#define I810_READ(reg) I810_DEREF(reg)
#define I810_WRITE(reg,val) do { I810_DEREF(reg) = val; } while (0)
-
-void i810_dma_init(drm_device_t *dev)
+#define I810_DEREF16(reg) *(__volatile__ u16 *)I810_ADDR(reg)
+#define I810_READ16(reg) I810_DEREF16(reg)
+#define I810_WRITE16(reg,val) do { I810_DEREF16(reg) = val; } while (0)
+
+#define RING_LOCALS unsigned int outring, ringmask; volatile char *virt;
+
+#define BEGIN_LP_RING(n) do { \
+ if (I810_VERBOSE) \
+ DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n", \
+ n, __FUNCTION__); \
+ if (dev_priv->ring.space < n*4) \
+ i810_wait_ring(dev, n*4); \
+ dev_priv->ring.space -= n*4; \
+ outring = dev_priv->ring.tail; \
+ ringmask = dev_priv->ring.tail_mask; \
+ virt = dev_priv->ring.virtual_start; \
+} while (0)
+
+#define ADVANCE_LP_RING() do { \
+ if (I810_VERBOSE) DRM_DEBUG("ADVANCE_LP_RING\n"); \
+ dev_priv->ring.tail = outring; \
+ I810_WRITE(LP_RING + RING_TAIL, outring); \
+} while(0)
+
+#define OUT_RING(n) do { \
+ if (I810_VERBOSE) DRM_DEBUG(" OUT_RING %x\n", (int)(n)); \
+ *(volatile unsigned int *)(virt + outring) = n; \
+ outring += 4; \
+ outring &= ringmask; \
+} while (0);
+
+static inline void i810_print_status_page(drm_device_t *dev)
{
- printk(KERN_INFO "i810_dma_init\n");
+ drm_device_dma_t *dma = dev->dma;
+ drm_i810_private_t *dev_priv = dev->dev_private;
+ u32 *temp = (u32 *)dev_priv->hw_status_page;
+ int i;
+
+ DRM_DEBUG( "hw_status: Interrupt Status : %x\n", temp[0]);
+ DRM_DEBUG( "hw_status: LpRing Head ptr : %x\n", temp[1]);
+ DRM_DEBUG( "hw_status: IRing Head ptr : %x\n", temp[2]);
+ DRM_DEBUG( "hw_status: Reserved : %x\n", temp[3]);
+ DRM_DEBUG( "hw_status: Driver Counter : %d\n", temp[5]);
+ for(i = 6; i < dma->buf_count + 6; i++) {
+ DRM_DEBUG( "buffer status idx : %d used: %d\n", i - 6, temp[i]);
+ }
}
-void i810_dma_cleanup(drm_device_t *dev)
+static drm_buf_t *i810_freelist_get(drm_device_t *dev)
{
- printk(KERN_INFO "i810_dma_cleanup\n");
+ drm_device_dma_t *dma = dev->dma;
+ int i;
+ int used;
+
+ /* Linear search might not be the best solution */
+
+ for (i = 0; i < dma->buf_count; i++) {
+ drm_buf_t *buf = dma->buflist[ i ];
+ drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+ /* In use is already a pointer */
+ used = cmpxchg(buf_priv->in_use, I810_BUF_FREE,
+ I810_BUF_USED);
+ if(used == I810_BUF_FREE) {
+ return buf;
+ }
+ }
+ return NULL;
}
-static inline void i810_dma_dispatch(drm_device_t *dev, unsigned long address,
- unsigned long length)
+/* This should only be called if the buffer is not sent to the hardware
+ * yet, the hardware updates in use for us once its on the ring buffer.
+ */
+
+static int i810_freelist_put(drm_device_t *dev, drm_buf_t *buf)
{
- printk(KERN_INFO "i810_dma_dispatch\n");
+ drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+ int used;
+
+ /* In use is already a pointer */
+ used = cmpxchg(buf_priv->in_use, I810_BUF_USED, I810_BUF_FREE);
+ if(used != I810_BUF_USED) {
+ DRM_ERROR("Freeing buffer thats not in use : %d\n", buf->idx);
+ return -EINVAL;
+ }
+
+ return 0;
}
-static inline void i810_dma_quiescent(drm_device_t *dev)
+static int i810_dma_get_buffers(drm_device_t *dev, drm_dma_t *d)
{
+ int i;
+ drm_buf_t *buf;
+
+ for (i = d->granted_count; i < d->request_count; i++) {
+ buf = i810_freelist_get(dev);
+ if (!buf) break;
+ buf->pid = current->pid;
+ copy_to_user_ret(&d->request_indices[i],
+ &buf->idx,
+ sizeof(buf->idx),
+ -EFAULT);
+ copy_to_user_ret(&d->request_sizes[i],
+ &buf->total,
+ sizeof(buf->total),
+ -EFAULT);
+ ++d->granted_count;
+ }
+ return 0;
}
-static inline void i810_dma_ready(drm_device_t *dev)
+static unsigned long i810_alloc_page(drm_device_t *dev)
{
- i810_dma_quiescent(dev);
- printk(KERN_INFO "i810_dma_ready\n");
+ unsigned long address;
+
+ address = __get_free_page(GFP_KERNEL);
+ if(address == 0UL)
+ return 0;
+
+ atomic_inc(&mem_map[MAP_NR((void *) address)].count);
+ set_bit(PG_locked, &mem_map[MAP_NR((void *) address)].flags);
+
+ return address;
}
-static inline int i810_dma_is_ready(drm_device_t *dev)
+static void i810_free_page(drm_device_t *dev, unsigned long page)
{
-
- i810_dma_quiescent(dev);
-
- printk(KERN_INFO "i810_dma_is_ready\n");
- return 1;
+ if(page == 0UL)
+ return;
+
+ atomic_dec(&mem_map[MAP_NR((void *) page)].count);
+ clear_bit(PG_locked, &mem_map[MAP_NR((void *) page)].flags);
+ wake_up(&mem_map[MAP_NR((void *) page)].wait);
+ free_page(page);
+ return;
}
-
-static void i810_dma_service(int irq, void *device, struct pt_regs *regs)
+static int i810_dma_cleanup(drm_device_t *dev)
{
- drm_device_t *dev = (drm_device_t *)device;
- drm_device_dma_t *dma = dev->dma;
-
- atomic_inc(&dev->total_irq);
- if (i810_dma_is_ready(dev)) {
- /* Free previous buffer */
- if (test_and_set_bit(0, &dev->dma_flag)) {
- atomic_inc(&dma->total_missed_free);
- return;
+ if(dev->dev_private) {
+ drm_i810_private_t *dev_priv =
+ (drm_i810_private_t *) dev->dev_private;
+
+ if(dev_priv->ring.virtual_start) {
+ drm_ioremapfree((void *) dev_priv->ring.virtual_start,
+ dev_priv->ring.Size);
}
- if (dma->this_buffer) {
- drm_free_buffer(dev, dma->this_buffer);
- dma->this_buffer = NULL;
+ if(dev_priv->hw_status_page != 0UL) {
+ i810_free_page(dev, dev_priv->hw_status_page);
+ /* Need to rewrite hardware status page */
+ I810_WRITE(0x02080, 0x1ffff000);
}
- clear_bit(0, &dev->dma_flag);
-
- /* Dispatch new buffer */
- queue_task(&dev->tq, &tq_immediate);
- mark_bh(IMMEDIATE_BH);
+ drm_free(dev->dev_private, sizeof(drm_i810_private_t),
+ DRM_MEM_DRIVER);
+ dev->dev_private = NULL;
}
+ return 0;
}
-/* Only called by i810_dma_schedule. */
-static int i810_do_dma(drm_device_t *dev, int locked)
+static int i810_wait_ring(drm_device_t *dev, int n)
{
- unsigned long address;
- unsigned long length;
- drm_buf_t *buf;
- int retcode = 0;
- drm_device_dma_t *dma = dev->dma;
-#if DRM_DMA_HISTOGRAM
- cycles_t dma_start, dma_stop;
-#endif
-
- if (test_and_set_bit(0, &dev->dma_flag)) {
- atomic_inc(&dma->total_missed_dma);
- return -EBUSY;
- }
-
-#if DRM_DMA_HISTOGRAM
- dma_start = get_cycles();
-#endif
-
- if (!dma->next_buffer) {
- DRM_ERROR("No next_buffer\n");
- clear_bit(0, &dev->dma_flag);
- return -EINVAL;
- }
-
- buf = dma->next_buffer;
- address = (unsigned long)buf->bus_address;
- length = buf->used;
+ drm_i810_private_t *dev_priv = dev->dev_private;
+ drm_i810_ring_buffer_t *ring = &(dev_priv->ring);
+ int iters = 0;
+ unsigned long end;
+
+ end = jiffies + (HZ*3);
+ while (ring->space < n) {
+ int i;
-
- DRM_DEBUG("context %d, buffer %d (%ld bytes)\n",
- buf->context, buf->idx, length);
-
- if (buf->list == DRM_LIST_RECLAIM) {
- drm_clear_next_buffer(dev);
- drm_free_buffer(dev, buf);
- clear_bit(0, &dev->dma_flag);
- return -EINVAL;
- }
-
- if (!length) {
- DRM_ERROR("0 length buffer\n");
- drm_clear_next_buffer(dev);
- drm_free_buffer(dev, buf);
- clear_bit(0, &dev->dma_flag);
- return 0;
- }
-
- if (!i810_dma_is_ready(dev)) {
- clear_bit(0, &dev->dma_flag);
- return -EBUSY;
- }
-
- if (buf->while_locked) {
- if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
- DRM_ERROR("Dispatching buffer %d from pid %d"
- " \"while locked\", but no lock held\n",
- buf->idx, buf->pid);
- }
- } else {
- if (!locked && !drm_lock_take(&dev->lock.hw_lock->lock,
- DRM_KERNEL_CONTEXT)) {
- atomic_inc(&dma->total_missed_lock);
- clear_bit(0, &dev->dma_flag);
- return -EBUSY;
+ ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+ ring->space = ring->head - (ring->tail+8);
+
+ if (ring->space < 0) ring->space += ring->Size;
+
+ iters++;
+ if((signed)(end - jiffies) <= 0) {
+ DRM_ERROR("space: %d wanted %d\n", ring->space, n);
+ DRM_ERROR("lockup\n");
+ goto out_wait_ring;
}
- }
-
- if (dev->last_context != buf->context
- && !(dev->queuelist[buf->context]->flags
- & _DRM_CONTEXT_PRESERVED)) {
- /* PRE: dev->last_context != buf->context */
- if (drm_context_switch(dev, dev->last_context, buf->context)) {
- drm_clear_next_buffer(dev);
- drm_free_buffer(dev, buf);
- }
- retcode = -EBUSY;
- goto cleanup;
-
- /* POST: we will wait for the context
- switch and will dispatch on a later call
- when dev->last_context == buf->context.
- NOTE WE HOLD THE LOCK THROUGHOUT THIS
- TIME! */
- }
-
- drm_clear_next_buffer(dev);
- buf->pending = 1;
- buf->waiting = 0;
- buf->list = DRM_LIST_PEND;
-#if DRM_DMA_HISTOGRAM
- buf->time_dispatched = get_cycles();
-#endif
- i810_dma_dispatch(dev, address, length);
- drm_free_buffer(dev, dma->this_buffer);
- dma->this_buffer = buf;
-
- atomic_add(length, &dma->total_bytes);
- atomic_inc(&dma->total_dmas);
-
- if (!buf->while_locked && !dev->context_flag && !locked) {
- if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
- DRM_KERNEL_CONTEXT)) {
- DRM_ERROR("\n");
- }
+ for (i = 0 ; i < 2000 ; i++) ;
}
-cleanup:
-
- clear_bit(0, &dev->dma_flag);
-#if DRM_DMA_HISTOGRAM
- dma_stop = get_cycles();
- atomic_inc(&dev->histo.dma[drm_histogram_slot(dma_stop - dma_start)]);
-#endif
-
- return retcode;
-}
-
-static void i810_dma_schedule_timer_wrapper(unsigned long dev)
-{
- i810_dma_schedule((drm_device_t *)dev, 0);
+out_wait_ring:
+ return iters;
}
-static void i810_dma_schedule_tq_wrapper(void *dev)
+static void i810_kernel_lost_context(drm_device_t *dev)
{
- i810_dma_schedule(dev, 0);
+ drm_i810_private_t *dev_priv = dev->dev_private;
+ drm_i810_ring_buffer_t *ring = &(dev_priv->ring);
+
+ ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+ ring->tail = I810_READ(LP_RING + RING_TAIL);
+ ring->space = ring->head - (ring->tail+8);
+ if (ring->space < 0) ring->space += ring->Size;
}
-int i810_dma_schedule(drm_device_t *dev, int locked)
+static int i810_freelist_init(drm_device_t *dev)
{
- int next;
- drm_queue_t *q;
- drm_buf_t *buf;
- int retcode = 0;
- int processed = 0;
- int missed;
- int expire = 20;
- drm_device_dma_t *dma = dev->dma;
-#if DRM_DMA_HISTOGRAM
- cycles_t schedule_start;
-#endif
-
- if (test_and_set_bit(0, &dev->interrupt_flag)) {
- /* Not reentrant */
- atomic_inc(&dma->total_missed_sched);
- return -EBUSY;
- }
- missed = atomic_read(&dma->total_missed_sched);
-
-#if DRM_DMA_HISTOGRAM
- schedule_start = get_cycles();
-#endif
-
-again:
- if (dev->context_flag) {
- clear_bit(0, &dev->interrupt_flag);
- return -EBUSY;
- }
- if (dma->next_buffer) {
- /* Unsent buffer that was previously
- selected, but that couldn't be sent
- because the lock could not be obtained
- or the DMA engine wasn't ready. Try
- again. */
- atomic_inc(&dma->total_tried);
- if (!(retcode = i810_do_dma(dev, locked))) {
- atomic_inc(&dma->total_hit);
- ++processed;
- }
- } else {
- do {
- next = drm_select_queue(dev,
- i810_dma_schedule_timer_wrapper);
- if (next >= 0) {
- q = dev->queuelist[next];
- buf = drm_waitlist_get(&q->waitlist);
- dma->next_buffer = buf;
- dma->next_queue = q;
- if (buf && buf->list == DRM_LIST_RECLAIM) {
- drm_clear_next_buffer(dev);
- drm_free_buffer(dev, buf);
- }
- }
- } while (next >= 0 && !dma->next_buffer);
- if (dma->next_buffer) {
- if (!(retcode = i810_do_dma(dev, locked))) {
- ++processed;
- }
- }
+ drm_device_dma_t *dma = dev->dma;
+ drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+ u8 *hw_status = (u8 *)dev_priv->hw_status_page;
+ int i;
+ int my_idx = 24;
+
+ if(dma->buf_count > 1019) {
+ /* Not enough space in the status page for the freelist */
+ return -EINVAL;
}
- if (--expire) {
- if (missed != atomic_read(&dma->total_missed_sched)) {
- atomic_inc(&dma->total_lost);
- if (i810_dma_is_ready(dev)) goto again;
- }
- if (processed && i810_dma_is_ready(dev)) {
- atomic_inc(&dma->total_lost);
- processed = 0;
- goto again;
- }
+ for (i = 0; i < dma->buf_count; i++) {
+ drm_buf_t *buf = dma->buflist[ i ];
+ drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+
+ buf_priv->in_use = hw_status + my_idx;
+ DRM_DEBUG("buf_priv->in_use : %p\n", buf_priv->in_use);
+ *buf_priv->in_use = I810_BUF_FREE;
+ buf_priv->my_use_idx = my_idx;
+ my_idx += 4;
}
-
- clear_bit(0, &dev->interrupt_flag);
-
-#if DRM_DMA_HISTOGRAM
- atomic_inc(&dev->histo.schedule[drm_histogram_slot(get_cycles()
- - schedule_start)]);
-#endif
- return retcode;
+ return 0;
}
-static int i810_dma_priority(drm_device_t *dev, drm_dma_t *d)
+static int i810_dma_initialize(drm_device_t *dev,
+ drm_i810_private_t *dev_priv,
+ drm_i810_init_t *init)
{
- unsigned long address;
- unsigned long length;
- int must_free = 0;
- int retcode = 0;
- int i;
- int idx;
- drm_buf_t *buf;
- drm_buf_t *last_buf = NULL;
- drm_device_dma_t *dma = dev->dma;
- DECLARE_WAITQUEUE(entry, current);
-
- /* Turn off interrupt handling */
- while (test_and_set_bit(0, &dev->interrupt_flag)) {
- schedule();
- if (signal_pending(current)) return -EINTR;
- }
- if (!(d->flags & _DRM_DMA_WHILE_LOCKED)) {
- while (!drm_lock_take(&dev->lock.hw_lock->lock,
- DRM_KERNEL_CONTEXT)) {
- schedule();
- if (signal_pending(current)) {
- clear_bit(0, &dev->interrupt_flag);
- return -EINTR;
- }
- }
- ++must_free;
- }
- atomic_inc(&dma->total_prio);
-
- for (i = 0; i < d->send_count; i++) {
- idx = d->send_indices[i];
- if (idx < 0 || idx >= dma->buf_count) {
- DRM_ERROR("Index %d (of %d max)\n",
- d->send_indices[i], dma->buf_count - 1);
- continue;
- }
- buf = dma->buflist[ idx ];
- if (buf->pid != current->pid) {
- DRM_ERROR("Process %d using buffer owned by %d\n",
- current->pid, buf->pid);
- retcode = -EINVAL;
- goto cleanup;
- }
- if (buf->list != DRM_LIST_NONE) {
- DRM_ERROR("Process %d using %d's buffer on list %d\n",
- current->pid, buf->pid, buf->list);
- retcode = -EINVAL;
- goto cleanup;
- }
- /* This isn't a race condition on
- buf->list, since our concern is the
- buffer reclaim during the time the
- process closes the /dev/drm? handle, so
- it can't also be doing DMA. */
- buf->list = DRM_LIST_PRIO;
- buf->used = d->send_sizes[i];
- buf->context = d->context;
- buf->while_locked = d->flags & _DRM_DMA_WHILE_LOCKED;
- address = (unsigned long)buf->address;
- length = buf->used;
- if (!length) {
- DRM_ERROR("0 length buffer\n");
- }
- if (buf->pending) {
- DRM_ERROR("Sending pending buffer:"
- " buffer %d, offset %d\n",
- d->send_indices[i], i);
- retcode = -EINVAL;
- goto cleanup;
- }
- if (buf->waiting) {
- DRM_ERROR("Sending waiting buffer:"
- " buffer %d, offset %d\n",
- d->send_indices[i], i);
- retcode = -EINVAL;
- goto cleanup;
- }
- buf->pending = 1;
-
- if (dev->last_context != buf->context
- && !(dev->queuelist[buf->context]->flags
- & _DRM_CONTEXT_PRESERVED)) {
- add_wait_queue(&dev->context_wait, &entry);
- current->state = TASK_INTERRUPTIBLE;
- /* PRE: dev->last_context != buf->context */
- drm_context_switch(dev, dev->last_context,
- buf->context);
- /* POST: we will wait for the context
- switch and will dispatch on a later call
- when dev->last_context == buf->context.
- NOTE WE HOLD THE LOCK THROUGHOUT THIS
- TIME! */
- schedule();
- current->state = TASK_RUNNING;
- remove_wait_queue(&dev->context_wait, &entry);
- if (signal_pending(current)) {
- retcode = -EINTR;
- goto cleanup;
- }
- if (dev->last_context != buf->context) {
- DRM_ERROR("Context mismatch: %d %d\n",
- dev->last_context,
- buf->context);
- }
- }
-
-#if DRM_DMA_HISTOGRAM
- buf->time_queued = get_cycles();
- buf->time_dispatched = buf->time_queued;
-#endif
- i810_dma_dispatch(dev, address, length);
- if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
- DRM_KERNEL_CONTEXT)) {
- DRM_ERROR("\n");
- }
-
- atomic_add(length, &dma->total_bytes);
- atomic_inc(&dma->total_dmas);
-
- if (last_buf) {
- drm_free_buffer(dev, last_buf);
- }
- last_buf = buf;
- }
+ drm_map_t *sarea_map;
+ dev->dev_private = (void *) dev_priv;
+ memset(dev_priv, 0, sizeof(drm_i810_private_t));
-cleanup:
- if (last_buf) {
- i810_dma_ready(dev);
- drm_free_buffer(dev, last_buf);
+ if (init->ring_map_idx >= dev->map_count ||
+ init->buffer_map_idx >= dev->map_count) {
+ i810_dma_cleanup(dev);
+ DRM_ERROR("ring_map or buffer_map are invalid\n");
+ return -EINVAL;
}
-
- if (must_free && !dev->context_flag) {
- if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
- DRM_KERNEL_CONTEXT)) {
- DRM_ERROR("\n");
- }
+
+ dev_priv->ring_map_idx = init->ring_map_idx;
+ dev_priv->buffer_map_idx = init->buffer_map_idx;
+ sarea_map = dev->maplist[0];
+ dev_priv->sarea_priv = (drm_i810_sarea_t *)
+ ((u8 *)sarea_map->handle +
+ init->sarea_priv_offset);
+
+ atomic_set(&dev_priv->flush_done, 0);
+ init_waitqueue_head(&dev_priv->flush_queue);
+
+ dev_priv->ring.Start = init->ring_start;
+ dev_priv->ring.End = init->ring_end;
+ dev_priv->ring.Size = init->ring_size;
+ dev_priv->ring.virtual_start = drm_ioremap(dev->agp->base +
+ init->ring_start,
+ init->ring_size);
+ dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
+
+ if (dev_priv->ring.virtual_start == NULL) {
+ i810_dma_cleanup(dev);
+ DRM_ERROR("can not ioremap virtual address for"
+ " ring buffer\n");
+ return -ENOMEM;
}
- clear_bit(0, &dev->interrupt_flag);
- return retcode;
+
+ /* Program Hardware Status Page */
+ dev_priv->hw_status_page = i810_alloc_page(dev);
+ memset((void *) dev_priv->hw_status_page, 0, PAGE_SIZE);
+ if(dev_priv->hw_status_page == 0UL) {
+ i810_dma_cleanup(dev);
+ DRM_ERROR("Can not allocate hardware status page\n");
+ return -ENOMEM;
+ }
+ DRM_DEBUG("hw status page @ %lx\n", dev_priv->hw_status_page);
+
+ I810_WRITE(0x02080, virt_to_bus((void *)dev_priv->hw_status_page));
+ DRM_DEBUG("Enabled hardware status page\n");
+
+ /* Now we need to init our freelist */
+ if(i810_freelist_init(dev) != 0) {
+ i810_dma_cleanup(dev);
+ DRM_ERROR("Not enough space in the status page for"
+ " the freelist\n");
+ return -ENOMEM;
+ }
+ return 0;
}
-static int i810_dma_send_buffers(drm_device_t *dev, drm_dma_t *d)
+int i810_dma_init(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
{
- DECLARE_WAITQUEUE(entry, current);
- drm_buf_t *last_buf = NULL;
- int retcode = 0;
- drm_device_dma_t *dma = dev->dma;
-
- if (d->flags & _DRM_DMA_BLOCK) {
- last_buf = dma->buflist[d->send_indices[d->send_count-1]];
- add_wait_queue(&last_buf->dma_wait, &entry);
- }
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_i810_private_t *dev_priv;
+ drm_i810_init_t init;
+ int retcode = 0;
- if ((retcode = drm_dma_enqueue(dev, d))) {
- if (d->flags & _DRM_DMA_BLOCK)
- remove_wait_queue(&last_buf->dma_wait, &entry);
- return retcode;
- }
-
- i810_dma_schedule(dev, 0);
+ copy_from_user_ret(&init, (drm_i810_init_t *)arg,
+ sizeof(init), -EFAULT);
- if (d->flags & _DRM_DMA_BLOCK) {
- DRM_DEBUG("%d waiting\n", current->pid);
- current->state = TASK_INTERRUPTIBLE;
- for (;;) {
- if (!last_buf->waiting
- && !last_buf->pending)
- break; /* finished */
- schedule();
- if (signal_pending(current)) {
- retcode = -EINTR; /* Can't restart */
- break;
- }
- }
- current->state = TASK_RUNNING;
- DRM_DEBUG("%d running\n", current->pid);
- remove_wait_queue(&last_buf->dma_wait, &entry);
- if (!retcode
- || (last_buf->list==DRM_LIST_PEND && !last_buf->pending)) {
- if (!waitqueue_active(&last_buf->dma_wait)) {
- drm_free_buffer(dev, last_buf);
- }
- }
- if (retcode) {
- DRM_ERROR("ctx%d w%d p%d c%d i%d l%d %d/%d\n",
- d->context,
- last_buf->waiting,
- last_buf->pending,
- DRM_WAITCOUNT(dev, d->context),
- last_buf->idx,
- last_buf->list,
- last_buf->pid,
- current->pid);
- }
+ switch(init.func) {
+ case I810_INIT_DMA:
+ dev_priv = drm_alloc(sizeof(drm_i810_private_t),
+ DRM_MEM_DRIVER);
+ if(dev_priv == NULL) return -ENOMEM;
+ retcode = i810_dma_initialize(dev, dev_priv, &init);
+ break;
+ case I810_CLEANUP_DMA:
+ retcode = i810_dma_cleanup(dev);
+ break;
+ default:
+ retcode = -EINVAL;
+ break;
}
- return retcode;
+
+ return retcode;
}
-int i810_dma(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
+static void i810_dma_dispatch_general(drm_device_t *dev, drm_buf_t *buf,
+ int used )
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->dev;
- drm_device_dma_t *dma = dev->dma;
- int retcode = 0;
- drm_dma_t d;
-
- printk("i810_dma start\n");
- copy_from_user_ret(&d, (drm_dma_t *)arg, sizeof(d), -EFAULT);
- DRM_DEBUG("%d %d: %d send, %d req\n",
- current->pid, d.context, d.send_count, d.request_count);
+ drm_i810_private_t *dev_priv = dev->dev_private;
+ drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+ unsigned long address = (unsigned long)buf->bus_address;
+ unsigned long start = address - dev->agp->base;
+ RING_LOCALS;
+
+ dev_priv->counter++;
+ DRM_DEBUG( "dispatch counter : %ld\n", dev_priv->counter);
+ DRM_DEBUG( "i810_dma_dispatch\n");
+ DRM_DEBUG( "start : 0x%lx\n", start);
+ DRM_DEBUG( "used : 0x%x\n", used);
+ DRM_DEBUG( "start + used - 4 : 0x%lx\n", start + used - 4);
+ i810_kernel_lost_context(dev);
+
+ BEGIN_LP_RING(10);
+ OUT_RING( CMD_OP_BATCH_BUFFER );
+ OUT_RING( start | BB1_PROTECTED );
+ OUT_RING( start + used - 4 );
+ OUT_RING( CMD_STORE_DWORD_IDX );
+ OUT_RING( 20 );
+ OUT_RING( dev_priv->counter );
+ OUT_RING( CMD_STORE_DWORD_IDX );
+ OUT_RING( buf_priv->my_use_idx );
+ OUT_RING( I810_BUF_FREE );
+ OUT_RING( CMD_REPORT_HEAD );
+ ADVANCE_LP_RING();
+}
- if (d.context == DRM_KERNEL_CONTEXT || d.context >= dev->queue_slots) {
- DRM_ERROR("Process %d using context %d\n",
- current->pid, d.context);
- return -EINVAL;
- }
+static void i810_dma_dispatch_vertex(drm_device_t *dev,
+ drm_buf_t *buf,
+ int discard,
+ int used)
+{
+ drm_i810_private_t *dev_priv = dev->dev_private;
+ drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+ drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
+ drm_clip_rect_t *box = sarea_priv->boxes;
+ int nbox = sarea_priv->nbox;
+ unsigned long address = (unsigned long)buf->bus_address;
+ unsigned long start = address - dev->agp->base;
+ int i = 0;
+ RING_LOCALS;
- if (d.send_count < 0 || d.send_count > dma->buf_count) {
- DRM_ERROR("Process %d trying to send %d buffers (of %d max)\n",
- current->pid, d.send_count, dma->buf_count);
- return -EINVAL;
- }
- if (d.request_count < 0 || d.request_count > dma->buf_count) {
- DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",
- current->pid, d.request_count, dma->buf_count);
- return -EINVAL;
+
+ if (nbox > I810_NR_SAREA_CLIPRECTS)
+ nbox = I810_NR_SAREA_CLIPRECTS;
+
+ DRM_DEBUG("dispatch vertex addr 0x%lx, used 0x%x nbox %d\n",
+ address, used, nbox);
+
+ dev_priv->counter++;
+ DRM_DEBUG( "dispatch counter : %ld\n", dev_priv->counter);
+ DRM_DEBUG( "i810_dma_dispatch\n");
+ DRM_DEBUG( "start : %lx\n", start);
+ DRM_DEBUG( "used : %d\n", used);
+ DRM_DEBUG( "start + used - 4 : %ld\n", start + used - 4);
+ i810_kernel_lost_context(dev);
+
+ if (used) {
+ do {
+ if (i < nbox) {
+ BEGIN_LP_RING(4);
+ OUT_RING( GFX_OP_SCISSOR | SC_UPDATE_SCISSOR |
+ SC_ENABLE );
+ OUT_RING( GFX_OP_SCISSOR_INFO );
+ OUT_RING( box[i].x1 | (box[i].y1 << 16) );
+ OUT_RING( (box[i].x2-1) | ((box[i].y2-1)<<16) );
+ ADVANCE_LP_RING();
+ }
+
+ BEGIN_LP_RING(4);
+ OUT_RING( CMD_OP_BATCH_BUFFER );
+ OUT_RING( start | BB1_PROTECTED );
+ OUT_RING( start + used - 4 );
+ OUT_RING( 0 );
+ ADVANCE_LP_RING();
+
+ } while (++i < nbox);
}
- if (d.send_count) {
-#if 0
- if (d.flags & _DRM_DMA_PRIORITY)
- retcode = i810_dma_priority(dev, &d);
- else
- retcode = i810_dma_send_buffers(dev, &d);
-#endif
- printk("i810_dma priority\n");
+ BEGIN_LP_RING(10);
+ OUT_RING( CMD_STORE_DWORD_IDX );
+ OUT_RING( 20 );
+ OUT_RING( dev_priv->counter );
+ OUT_RING( 0 );
- retcode = i810_dma_priority(dev, &d);
+ if (discard) {
+ OUT_RING( CMD_STORE_DWORD_IDX );
+ OUT_RING( buf_priv->my_use_idx );
+ OUT_RING( I810_BUF_FREE );
+ OUT_RING( 0 );
}
- d.granted_count = 0;
+ OUT_RING( CMD_REPORT_HEAD );
+ OUT_RING( 0 );
+ ADVANCE_LP_RING();
+}
- if (!retcode && d.request_count) {
- retcode = drm_dma_get_buffers(dev, &d);
- }
- DRM_DEBUG("%d returning, granted = %d\n",
- current->pid, d.granted_count);
- copy_to_user_ret((drm_dma_t *)arg, &d, sizeof(d), -EFAULT);
+/* Interrupts are only for flushing */
+static void i810_dma_service(int irq, void *device, struct pt_regs *regs)
+{
+ drm_device_t *dev = (drm_device_t *)device;
+ u16 temp;
+
+ atomic_inc(&dev->total_irq);
+ temp = I810_READ16(I810REG_INT_IDENTITY_R);
+ temp = temp & ~(0x6000);
+ if(temp != 0) I810_WRITE16(I810REG_INT_IDENTITY_R,
+ temp); /* Clear all interrupts */
+
+ queue_task(&dev->tq, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+}
- printk("i810_dma end (granted)\n");
- return retcode;
+static void i810_dma_task_queue(void *device)
+{
+ drm_device_t *dev = (drm_device_t *) device;
+ drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+
+ atomic_set(&dev_priv->flush_done, 1);
+ wake_up_interruptible(&dev_priv->flush_queue);
}
int i810_irq_install(drm_device_t *dev, int irq)
{
int retcode;
-
+ u16 temp;
+
if (!irq) return -EINVAL;
down(&dev->struct_sem);
@@ -591,6 +508,7 @@ int i810_irq_install(drm_device_t *dev, int irq)
dev->irq = irq;
up(&dev->struct_sem);
+ DRM_DEBUG( "Interrupt Install : %d\n", irq);
DRM_DEBUG("%d\n", irq);
dev->context_flag = 0;
@@ -603,12 +521,21 @@ int i810_irq_install(drm_device_t *dev, int irq)
dev->tq.next = NULL;
dev->tq.sync = 0;
- dev->tq.routine = i810_dma_schedule_tq_wrapper;
+ dev->tq.routine = i810_dma_task_queue;
dev->tq.data = dev;
-
/* Before installing handler */
- /* TODO */
+ temp = I810_READ16(I810REG_HWSTAM);
+ temp = temp & 0x6000;
+ I810_WRITE16(I810REG_HWSTAM, temp);
+
+ temp = I810_READ16(I810REG_INT_MASK_R);
+ temp = temp & 0x6000;
+ I810_WRITE16(I810REG_INT_MASK_R, temp); /* Unmask interrupts */
+ temp = I810_READ16(I810REG_INT_ENABLE_R);
+ temp = temp & 0x6000;
+ I810_WRITE16(I810REG_INT_ENABLE_R, temp); /* Disable all interrupts */
+
/* Install handler */
if ((retcode = request_irq(dev->irq,
i810_dma_service,
@@ -620,15 +547,18 @@ int i810_irq_install(drm_device_t *dev, int irq)
up(&dev->struct_sem);
return retcode;
}
-
- /* After installing handler */
- /* TODO */
+ temp = I810_READ16(I810REG_INT_ENABLE_R);
+ temp = temp & 0x6000;
+ temp = temp | 0x0003;
+ I810_WRITE16(I810REG_INT_ENABLE_R,
+ temp); /* Enable bp & user interrupts */
return 0;
}
int i810_irq_uninstall(drm_device_t *dev)
{
int irq;
+ u16 temp;
down(&dev->struct_sem);
irq = dev->irq;
@@ -636,16 +566,25 @@ int i810_irq_uninstall(drm_device_t *dev)
up(&dev->struct_sem);
if (!irq) return -EINVAL;
-
+
+ DRM_DEBUG( "Interrupt UnInstall: %d\n", irq);
DRM_DEBUG("%d\n", irq);
-
- /* TODO : Disable interrupts */
+
+ temp = I810_READ16(I810REG_INT_IDENTITY_R);
+ temp = temp & ~(0x6000);
+ if(temp != 0) I810_WRITE16(I810REG_INT_IDENTITY_R,
+ temp); /* Clear all interrupts */
+
+ temp = I810_READ16(I810REG_INT_ENABLE_R);
+ temp = temp & 0x6000;
+ I810_WRITE16(I810REG_INT_ENABLE_R,
+ temp); /* Disable all interrupts */
+
free_irq(irq, dev);
return 0;
}
-
int i810_control(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long arg)
{
@@ -654,8 +593,7 @@ int i810_control(struct inode *inode, struct file *filp, unsigned int cmd,
drm_control_t ctl;
int retcode;
- printk(KERN_INFO "i810_control\n");
- i810_dma_init(dev);
+ DRM_DEBUG( "i810_control\n");
copy_from_user_ret(&ctl, (drm_control_t *)arg, sizeof(ctl), -EFAULT);
@@ -674,20 +612,134 @@ int i810_control(struct inode *inode, struct file *filp, unsigned int cmd,
return 0;
}
+static inline void i810_dma_emit_flush(drm_device_t *dev)
+{
+ drm_i810_private_t *dev_priv = dev->dev_private;
+ RING_LOCALS;
+
+ i810_kernel_lost_context(dev);
+ BEGIN_LP_RING(2);
+ OUT_RING( CMD_REPORT_HEAD );
+ OUT_RING( GFX_OP_USER_INTERRUPT );
+ ADVANCE_LP_RING();
+}
+
+static inline void i810_dma_quiescent_emit(drm_device_t *dev)
+{
+ drm_i810_private_t *dev_priv = dev->dev_private;
+ RING_LOCALS;
+
+ i810_kernel_lost_context(dev);
+ BEGIN_LP_RING(4);
+
+ OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE );
+ OUT_RING( CMD_REPORT_HEAD );
+ OUT_RING( GFX_OP_USER_INTERRUPT );
+ OUT_RING( 0 );
+ ADVANCE_LP_RING();
+}
+
+static void i810_dma_quiescent(drm_device_t *dev)
+{
+ DECLARE_WAITQUEUE(entry, current);
+ drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+ unsigned long end;
+
+ if(dev_priv == NULL) {
+ return;
+ }
+ atomic_set(&dev_priv->flush_done, 0);
+ current->state = TASK_INTERRUPTIBLE;
+ add_wait_queue(&dev_priv->flush_queue, &entry);
+ end = jiffies + (HZ*3);
+
+ for (;;) {
+ i810_dma_quiescent_emit(dev);
+ if (atomic_read(&dev_priv->flush_done) == 1) break;
+ if((signed)(end - jiffies) <= 0) {
+ DRM_ERROR("lockup\n");
+ break;
+ }
+ schedule_timeout(HZ*3);
+ if (signal_pending(current)) {
+ break;
+ }
+ }
+
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&dev_priv->flush_queue, &entry);
+
+ return;
+}
+
+static int i810_flush_queue(drm_device_t *dev)
+{
+ DECLARE_WAITQUEUE(entry, current);
+ drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+ unsigned long end;
+ int ret = 0;
+
+ if(dev_priv == NULL) {
+ return 0;
+ }
+ atomic_set(&dev_priv->flush_done, 0);
+ current->state = TASK_INTERRUPTIBLE;
+ add_wait_queue(&dev_priv->flush_queue, &entry);
+ end = jiffies + (HZ*3);
+ for (;;) {
+ i810_dma_emit_flush(dev);
+ if (atomic_read(&dev_priv->flush_done) == 1) break;
+ if((signed)(end - jiffies) <= 0) {
+ DRM_ERROR("lockup\n");
+ break;
+ }
+ schedule_timeout(HZ*3);
+ if (signal_pending(current)) {
+ ret = -EINTR; /* Can't restart */
+ break;
+ }
+ }
+
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&dev_priv->flush_queue, &entry);
+
+ return ret;
+}
+
+/* Must be called with the lock held */
+void i810_reclaim_buffers(drm_device_t *dev, pid_t pid)
+{
+ drm_device_dma_t *dma = dev->dma;
+ int i;
+
+ if (!dma) return;
+ if(dev->dev_private == NULL) return;
+
+ i810_flush_queue(dev);
+
+ for (i = 0; i < dma->buf_count; i++) {
+ drm_buf_t *buf = dma->buflist[ i ];
+ drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+
+ if (buf->pid == pid) {
+ /* Only buffers that need to get reclaimed ever
+ * get set to free */
+ if(buf_priv == NULL) return;
+ cmpxchg(buf_priv->in_use,
+ I810_BUF_USED, I810_BUF_FREE);
+ }
+ }
+}
+
int i810_lock(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long arg)
{
drm_file_t *priv = filp->private_data;
drm_device_t *dev = priv->dev;
+
DECLARE_WAITQUEUE(entry, current);
int ret = 0;
drm_lock_t lock;
- drm_queue_t *q;
-#if DRM_DMA_HISTOGRAM
- cycles_t start;
-
- dev->lck_start = start = get_cycles();
-#endif
copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT);
@@ -696,16 +748,20 @@ int i810_lock(struct inode *inode, struct file *filp, unsigned int cmd,
current->pid, lock.context);
return -EINVAL;
}
+
+ DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n",
+ lock.context, current->pid, dev->lock.hw_lock->lock,
+ lock.flags);
- if (lock.context < 0 || lock.context >= dev->queue_count) {
+ if (lock.context < 0) {
return -EINVAL;
}
- q = dev->queuelist[lock.context];
-
- ret = drm_flush_block_and_flush(dev, lock.context, lock.flags);
+ /* Only one queue:
+ */
if (!ret) {
- if (_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)
+#if 0
+ if (_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)
!= lock.context) {
long j = jiffies - dev->lock.lock_time;
@@ -716,6 +772,7 @@ int i810_lock(struct inode *inode, struct file *filp, unsigned int cmd,
schedule_timeout(j);
}
}
+#endif
add_wait_queue(&dev->lock.lock_queue, &entry);
for (;;) {
if (!dev->lock.hw_lock) {
@@ -728,13 +785,13 @@ int i810_lock(struct inode *inode, struct file *filp, unsigned int cmd,
dev->lock.pid = current->pid;
dev->lock.lock_time = jiffies;
atomic_inc(&dev->total_locks);
- atomic_inc(&q->total_locks);
break; /* Got lock */
}
/* Contention */
atomic_inc(&dev->total_sleeps);
current->state = TASK_INTERRUPTIBLE;
+ DRM_DEBUG("Calling lock schedule\n");
schedule();
if (signal_pending(current)) {
ret = -ERESTARTSYS;
@@ -744,19 +801,184 @@ int i810_lock(struct inode *inode, struct file *filp, unsigned int cmd,
current->state = TASK_RUNNING;
remove_wait_queue(&dev->lock.lock_queue, &entry);
}
-
- drm_flush_unblock(dev, lock.context, lock.flags); /* cleanup phase */
if (!ret) {
- if (lock.flags & _DRM_LOCK_READY)
- i810_dma_ready(dev);
- if (lock.flags & _DRM_LOCK_QUIESCENT)
- i810_dma_quiescent(dev);
+ if (lock.flags & _DRM_LOCK_QUIESCENT) {
+ DRM_DEBUG("_DRM_LOCK_QUIESCENT\n");
+ DRM_DEBUG("fred\n");
+ i810_dma_quiescent(dev);
+ }
}
+ DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock");
+ return ret;
+}
-#if DRM_DMA_HISTOGRAM
- atomic_inc(&dev->histo.lacq[drm_histogram_slot(get_cycles() - start)]);
-#endif
+int i810_flush_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+
+ DRM_DEBUG("i810_flush_ioctl\n");
+ if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+ DRM_ERROR("i810_flush_ioctl called without lock held\n");
+ return -EINVAL;
+ }
+
+ i810_flush_queue(dev);
+ return 0;
+}
+
+static int i810DmaGeneral(drm_device_t *dev, drm_i810_general_t *args)
+{
+ drm_device_dma_t *dma = dev->dma;
+ drm_buf_t *buf = dma->buflist[ args->idx ];
+
+ if (!args->used) {
+ i810_freelist_put(dev, buf);
+ } else {
+ i810_dma_dispatch_general( dev, buf, args->used );
+ atomic_add(args->used, &dma->total_bytes);
+ atomic_inc(&dma->total_dmas);
+ }
+ return 0;
+}
+
+static int i810DmaVertex(drm_device_t *dev, drm_i810_vertex_t *args)
+{
+ drm_device_dma_t *dma = dev->dma;
+ drm_buf_t *buf = dma->buflist[ args->idx ];
+ i810_dma_dispatch_vertex( dev, buf, args->discard, args->used );
+ atomic_add(args->used, &dma->total_bytes);
+ atomic_inc(&dma->total_dmas);
+ return 0;
+}
+
+int i810_dma_general(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_i810_general_t general;
+ drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+ u32 *hw_status = (u32 *)dev_priv->hw_status_page;
+ drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
+ dev_priv->sarea_priv;
+
+ int retcode = 0;
- return ret;
+ copy_from_user_ret(&general, (drm_i810_general_t *)arg, sizeof(general),
+ -EFAULT);
+
+ DRM_DEBUG("i810 dma general idx %d used %d\n",
+ general.idx, general.used);
+
+ if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+ DRM_ERROR("i810_dma_general called without lock held\n");
+ return -EINVAL;
+ }
+
+ retcode = i810DmaGeneral(dev, &general);
+ sarea_priv->last_enqueue = dev_priv->counter-1;
+ sarea_priv->last_dispatch = (int) hw_status[5];
+
+ return retcode;
+}
+
+int i810_dma_vertex(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+ u32 *hw_status = (u32 *)dev_priv->hw_status_page;
+ drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
+ dev_priv->sarea_priv;
+ drm_i810_vertex_t vertex;
+ int retcode = 0;
+
+ copy_from_user_ret(&vertex, (drm_i810_vertex_t *)arg, sizeof(vertex),
+ -EFAULT);
+ if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+ DRM_ERROR("i810_dma_vertex called without lock held\n");
+ return -EINVAL;
+ }
+
+ DRM_DEBUG("i810 dma vertex, idx %d used %d discard %d\n",
+ vertex.idx, vertex.used, vertex.discard);
+
+ retcode = i810DmaVertex(dev, &vertex);
+ sarea_priv->last_enqueue = dev_priv->counter-1;
+ sarea_priv->last_dispatch = (int) hw_status[5];
+
+ return retcode;
+
+}
+
+int i810_getage(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+ u32 *hw_status = (u32 *)dev_priv->hw_status_page;
+ drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
+ dev_priv->sarea_priv;
+
+ sarea_priv->last_dispatch = (int) hw_status[5];
+ return 0;
+}
+
+int i810_dma(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_device_dma_t *dma = dev->dma;
+ int retcode = 0;
+ drm_dma_t d;
+ drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+ u32 *hw_status = (u32 *)dev_priv->hw_status_page;
+ drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
+ dev_priv->sarea_priv;
+
+
+ copy_from_user_ret(&d, (drm_dma_t *)arg, sizeof(d), -EFAULT);
+ DRM_DEBUG("%d %d: %d send, %d req\n",
+ current->pid, d.context, d.send_count, d.request_count);
+
+ if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+ DRM_ERROR("i810_dma called without lock held\n");
+ return -EINVAL;
+ }
+
+ /* Please don't send us buffers.
+ */
+ if (d.send_count != 0) {
+ DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n",
+ current->pid, d.send_count);
+ return -EINVAL;
+ }
+
+ /* We'll send you buffers.
+ */
+ if (d.request_count < 0 || d.request_count > dma->buf_count) {
+ DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",
+ current->pid, d.request_count, dma->buf_count);
+ return -EINVAL;
+ }
+
+ d.granted_count = 0;
+
+ if (!retcode && d.request_count) {
+ retcode = i810_dma_get_buffers(dev, &d);
+ }
+
+ DRM_DEBUG("i810_dma: %d returning, granted = %d\n",
+ current->pid, d.granted_count);
+
+ copy_to_user_ret((drm_dma_t *)arg, &d, sizeof(d), -EFAULT);
+ sarea_priv->last_dispatch = (int) hw_status[5];
+
+ return retcode;
}
diff --git a/linux-core/i810_drm.h b/linux-core/i810_drm.h
new file mode 100644
index 00000000..0754874c
--- /dev/null
+++ b/linux-core/i810_drm.h
@@ -0,0 +1,93 @@
+#ifndef _I810_DRM_H_
+#define _I810_DRM_H_
+
+/* WARNING: These defines must be the same as what the Xserver uses.
+ * if you change them, you must change the defines in the Xserver.
+ */
+
+/* Might one day want to support the client-side ringbuffer code again.
+ */
+#ifndef _I810_DEFINES_
+#define _I810_DEFINES_
+
+#define I810_USE_BATCH 1
+#define I810_DMA_BUF_ORDER 12
+#define I810_DMA_BUF_SZ (1<<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
+#endif
+
+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;
+
+/* Warning: If you change the SAREA structure you must change the Xserver
+ * structure as well */
+
+typedef struct _drm_i810_tex_region {
+ 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 */
+} drm_i810_tex_region_t;
+
+typedef struct _drm_i810_sarea {
+ unsigned int nbox;
+ drm_clip_rect_t 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.
+ */
+
+ drm_i810_tex_region_t 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 _drm_i810_general {
+ int idx;
+ int used;
+} drm_i810_general_t;
+
+/* These may be placeholders if we have more cliprects than
+ * I810_NR_SAREA_CLIPRECTS. In that case, the client sets discard to
+ * false, indicating that the buffer will be dispatched again with a
+ * new set of cliprects.
+ */
+typedef struct _drm_i810_vertex {
+ int idx; /* buffer index */
+ int used; /* nr bytes in use */
+ int discard; /* client is finished with the buffer? */
+} drm_i810_vertex_t;
+
+#endif /* _I810_DRM_H_ */
diff --git a/linux-core/i810_drv.c b/linux-core/i810_drv.c
index f33153a3..d3b35c49 100644
--- a/linux-core/i810_drv.c
+++ b/linux-core/i810_drv.c
@@ -33,11 +33,13 @@
#define EXPORT_SYMTAB
#include "drmP.h"
#include "i810_drv.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 +56,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 +83,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 +107,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 +129,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 +372,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 +380,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 +403,6 @@ int i810_init(void)
i810_takedown(dev);
return retcode;
}
-#if 0
- printk("doing i810_dma_init\n");
- i810_dma_init(dev);
-#endif
DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
I810_NAME,
@@ -417,7 +430,6 @@ void i810_cleanup(void)
DRM_INFO("Module unloaded\n");
}
drm_ctxbitmap_cleanup(dev);
- i810_dma_cleanup(dev);
i810_takedown(dev);
if (dev->agp) {
drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS);
@@ -484,24 +496,82 @@ int i810_release(struct inode *inode, struct file *filp)
drm_device_t *dev = priv->dev;
int retcode = 0;
- DRM_DEBUG("open_count = %d\n", dev->open_count);
- if (!(retcode = drm_release(inode, filp))) {
- MOD_DEC_USE_COUNT;
- atomic_inc(&dev->total_close);
- spin_lock(&dev->count_lock);
- if (!--dev->open_count) {
- if (atomic_read(&dev->ioctl_count) || dev->blocked) {
- DRM_ERROR("Device busy: %d %d\n",
- atomic_read(&dev->ioctl_count),
- dev->blocked);
- spin_unlock(&dev->count_lock);
- return -EBUSY;
+ DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n",
+ current->pid, dev->device, dev->open_count);
+
+ if (_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)
+ && dev->lock.pid == current->pid) {
+ i810_reclaim_buffers(dev, priv->pid);
+ DRM_ERROR("Process %d dead, freeing lock for context %d\n",
+ current->pid,
+ _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+ drm_lock_free(dev,
+ &dev->lock.hw_lock->lock,
+ _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+
+ /* FIXME: may require heavy-handed reset of
+ hardware at this point, possibly
+ processed via a callback to the X
+ server. */
+ } else {
+ /* The lock is required to reclaim buffers */
+ DECLARE_WAITQUEUE(entry, current);
+ add_wait_queue(&dev->lock.lock_queue, &entry);
+ for (;;) {
+ if (!dev->lock.hw_lock) {
+ /* Device has been unregistered */
+ retcode = -EINTR;
+ break;
+ }
+ if (drm_lock_take(&dev->lock.hw_lock->lock,
+ DRM_KERNEL_CONTEXT)) {
+ dev->lock.pid = priv->pid;
+ dev->lock.lock_time = jiffies;
+ atomic_inc(&dev->total_locks);
+ break; /* Got lock */
+ }
+ /* Contention */
+ atomic_inc(&dev->total_sleeps);
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ if (signal_pending(current)) {
+ retcode = -ERESTARTSYS;
+ break;
}
- spin_unlock(&dev->count_lock);
- return i810_takedown(dev);
}
- spin_unlock(&dev->count_lock);
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&dev->lock.lock_queue, &entry);
+ if(!retcode) {
+ i810_reclaim_buffers(dev, priv->pid);
+ drm_lock_free(dev, &dev->lock.hw_lock->lock,
+ DRM_KERNEL_CONTEXT);
+ }
+ }
+ drm_fasync(-1, filp, 0);
+
+ down(&dev->struct_sem);
+ if (priv->prev) priv->prev->next = priv->next;
+ else dev->file_first = priv->next;
+ if (priv->next) priv->next->prev = priv->prev;
+ else dev->file_last = priv->prev;
+ up(&dev->struct_sem);
+
+ drm_free(priv, sizeof(*priv), DRM_MEM_FILES);
+ MOD_DEC_USE_COUNT;
+ atomic_inc(&dev->total_close);
+ spin_lock(&dev->count_lock);
+ if (!--dev->open_count) {
+ if (atomic_read(&dev->ioctl_count) || dev->blocked) {
+ DRM_ERROR("Device busy: %d %d\n",
+ atomic_read(&dev->ioctl_count),
+ dev->blocked);
+ spin_unlock(&dev->count_lock);
+ return -EBUSY;
+ }
+ spin_unlock(&dev->count_lock);
+ return i810_takedown(dev);
}
+ spin_unlock(&dev->count_lock);
return retcode;
}
@@ -566,8 +636,7 @@ int i810_unlock(struct inode *inode, struct file *filp, unsigned int cmd,
atomic_inc(&dev->total_unlocks);
if (_DRM_LOCK_IS_CONT(dev->lock.hw_lock->lock))
atomic_inc(&dev->total_contends);
- drm_lock_transfer(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT);
- i810_dma_schedule(dev, 1);
+ drm_lock_transfer(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT);
if (!dev->context_flag) {
if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
DRM_KERNEL_CONTEXT)) {
diff --git a/linux-core/i810_drv.h b/linux-core/i810_drv.h
index 0f5f42bb..1badd36b 100644
--- a/linux-core/i810_drv.h
+++ b/linux-core/i810_drv.h
@@ -32,6 +32,31 @@
#ifndef _I810_DRV_H_
#define _I810_DRV_H_
+typedef struct _drm_i810_ring_buffer{
+ int tail_mask;
+ unsigned long Start;
+ unsigned long End;
+ unsigned long Size;
+ u8 *virtual_start;
+ int head;
+ int tail;
+ int space;
+} drm_i810_ring_buffer_t;
+
+typedef struct drm_i810_private {
+ int ring_map_idx;
+ int buffer_map_idx;
+
+ drm_i810_ring_buffer_t ring;
+ drm_i810_sarea_t *sarea_priv;
+
+ unsigned long hw_status_page;
+ unsigned long counter;
+
+ atomic_t flush_done;
+ wait_queue_head_t flush_queue; /* Processes waiting until flush */
+} drm_i810_private_t;
+
/* i810_drv.c */
extern int i810_init(void);
extern void i810_cleanup(void);
@@ -54,8 +79,13 @@ extern int i810_control(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern int i810_lock(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
-extern void i810_dma_init(drm_device_t *dev);
-extern void i810_dma_cleanup(drm_device_t *dev);
+extern int i810_dma_init(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int i810_flush_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern void i810_reclaim_buffers(drm_device_t *dev, pid_t pid);
+extern int i810_getage(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg);
/* i810_bufs.c */
@@ -72,5 +102,103 @@ extern int i810_mapbufs(struct inode *inode, struct file *filp,
extern int i810_addmap(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
+ /* i810_context.c */
+extern int i810_resctx(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int i810_addctx(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int i810_modctx(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int i810_getctx(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int i810_switchctx(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int i810_newctx(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int i810_rmctx(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+
+extern int i810_context_switch(drm_device_t *dev, int old, int new);
+extern int i810_context_switch_complete(drm_device_t *dev, int new);
+
+
+
+
+/* Copy the outstanding cliprects for every I810_DMA_VERTEX buffer.
+ * This can be fixed by emitting directly to the ringbuffer in the
+ * 'vertex_dma' ioctl.
+*/
+typedef struct {
+ u32 *in_use;
+ int my_use_idx;
+} drm_i810_buf_priv_t;
+
+
+#define I810_DMA_GENERAL 0
+#define I810_DMA_VERTEX 1
+#define I810_DMA_DISCARD 2 /* not used */
+
+#define I810_VERBOSE 0
+
+
+int i810_dma_vertex(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+
+int i810_dma_general(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+
+
+#define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23))
+#define GFX_OP_BREAKPOINT_INTERRUPT ((0<<29)|(1<<23))
+#define CMD_REPORT_HEAD (7<<23)
+#define CMD_STORE_DWORD_IDX ((0x21<<23) | 0x1)
+#define CMD_OP_BATCH_BUFFER ((0x0<<29)|(0x30<<23)|0x1)
+
+#define INST_PARSER_CLIENT 0x00000000
+#define INST_OP_FLUSH 0x02000000
+#define INST_FLUSH_MAP_CACHE 0x00000001
+
+
+#define BB1_START_ADDR_MASK (~0x7)
+#define BB1_PROTECTED (1<<0)
+#define BB1_UNPROTECTED (0<<0)
+#define BB2_END_ADDR_MASK (~0x7)
+
+#define I810REG_HWSTAM 0x02098
+#define I810REG_INT_IDENTITY_R 0x020a4
+#define I810REG_INT_MASK_R 0x020a8
+#define I810REG_INT_ENABLE_R 0x020a0
+
+#define LP_RING 0x2030
+#define HP_RING 0x2040
+#define RING_TAIL 0x00
+#define TAIL_ADDR 0x000FFFF8
+#define RING_HEAD 0x04
+#define HEAD_WRAP_COUNT 0xFFE00000
+#define HEAD_WRAP_ONE 0x00200000
+#define HEAD_ADDR 0x001FFFFC
+#define RING_START 0x08
+#define START_ADDR 0x00FFFFF8
+#define RING_LEN 0x0C
+#define RING_NR_PAGES 0x000FF000
+#define RING_REPORT_MASK 0x00000006
+#define RING_REPORT_64K 0x00000002
+#define RING_REPORT_128K 0x00000004
+#define RING_NO_REPORT 0x00000000
+#define RING_VALID_MASK 0x00000001
+#define RING_VALID 0x00000001
+#define RING_INVALID 0x00000000
+
+#define GFX_OP_SCISSOR ((0x3<<29)|(0x1c<<24)|(0x10<<19))
+#define SC_UPDATE_SCISSOR (0x1<<1)
+#define SC_ENABLE_MASK (0x1<<0)
+#define SC_ENABLE (0x1<<0)
+
+#define GFX_OP_SCISSOR_INFO ((0x3<<29)|(0x1d<<24)|(0x81<<16)|(0x1))
+#define SCI_YMIN_MASK (0xffff<<16)
+#define SCI_XMIN_MASK (0xffff<<0)
+#define SCI_YMAX_MASK (0xffff<<16)
+#define SCI_XMAX_MASK (0xffff<<0)
#endif
+
diff --git a/linux-core/mga_drv.c b/linux-core/mga_drv.c
index 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/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);
}