Patch for tdfx

From: john.cavan@sympatico.ca
Date: Sat Jul 15 2000 - 18:11:18 EST


This patch brings the DRM code for the Voodoo card up to date with the
code from the DRI project. I didn't patch in the other cards, I have no
way of testing them, nor did I update the other code (3DLabs and the Sun
driver) for the same reason. It seems to be mostly functional on my
machine, at least windowed 3D acceleration under XFree86 4.0.1 is
working, but mileage may vary and I have no idea what impact this has to
the 3DLabs and other cards. At the very least, maybe it will push
someone into doing the same.

John

P.S. I was going to do the BTTV stuff, but that is apparently handled. I
tried it, it works for me as well.

diff -urN linux.clean/drivers/char/drm/Makefile linux/drivers/char/drm/Makefile
--- linux.clean/drivers/char/drm/Makefile Wed Jun 21 13:10:02 2000
+++ linux/drivers/char/drm/Makefile Sat Jul 15 14:36:16 2000
@@ -13,7 +13,11 @@
 O_TARGET := drm.o
 
 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
+
+ifdef CONFIG_AGP
+L_OBJS += agpsupport.o
+endif
 
 M_OBJS :=
 
diff -urN linux.clean/drivers/char/drm/agpsupport.c linux/drivers/char/drm/agpsupport.c
--- linux.clean/drivers/char/drm/agpsupport.c Wed Dec 31 19:00:00 1969
+++ linux/drivers/char/drm/agpsupport.c Sat Jul 15 14:40:49 2000
@@ -0,0 +1,315 @@
+/* agpsupport.c -- DRM support for AGP/GART backend -*- linux-c -*-
+ * Created: Mon Dec 13 09:56:45 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Rickard E. (Rik) Faith <faith@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+drm_agp_func_t drm_agp = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
+
+/* The C standard says that 'void *' is not guaranteed to hold a function
+ pointer, so we use this union to define a generic pointer that is
+ guaranteed to hold any of the function pointers we care about. */
+typedef union {
+ 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 *);
+ unsigned long address;
+} drm_agp_func_u;
+
+typedef struct drm_agp_fill {
+ const char *name;
+ drm_agp_func_u *f;
+} drm_agp_fill_t;
+
+static drm_agp_fill_t drm_agp_fill[] = {
+ { __MODULE_STRING(agp_free_memory),
+ (drm_agp_func_u *)&drm_agp.free_memory },
+ { __MODULE_STRING(agp_allocate_memory),
+ (drm_agp_func_u *)&drm_agp.allocate_memory },
+ { __MODULE_STRING(agp_bind_memory),
+ (drm_agp_func_u *)&drm_agp.bind_memory },
+ { __MODULE_STRING(agp_unbind_memory),
+ (drm_agp_func_u *)&drm_agp.unbind_memory },
+ { __MODULE_STRING(agp_enable),
+ (drm_agp_func_u *)&drm_agp.enable },
+ { __MODULE_STRING(agp_backend_acquire),
+ (drm_agp_func_u *)&drm_agp.acquire },
+ { __MODULE_STRING(agp_backend_release),
+ (drm_agp_func_u *)&drm_agp.release },
+ { __MODULE_STRING(agp_copy_info),
+ (drm_agp_func_u *)&drm_agp.copy_info },
+ { NULL, NULL }
+};
+
+int drm_agp_info(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;
+ agp_kern_info *kern;
+ drm_agp_info_t info;
+
+ if (!dev->agp->acquired || !drm_agp.copy_info) return -EINVAL;
+
+ kern = &dev->agp->agp_info;
+ info.agp_version_major = kern->version.major;
+ info.agp_version_minor = kern->version.minor;
+ info.mode = kern->mode;
+ info.aperture_base = kern->aper_base;
+ info.aperture_size = kern->aper_size * 1024 * 1024;
+ info.memory_allowed = kern->max_memory << PAGE_SHIFT;
+ info.memory_used = kern->current_memory << PAGE_SHIFT;
+ info.id_vendor = kern->device->vendor;
+ info.id_device = kern->device->device;
+
+ copy_to_user_ret((drm_agp_info_t *)arg, &info, sizeof(info), -EFAULT);
+ return 0;
+}
+
+int drm_agp_acquire(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;
+ int retcode;
+
+ if (dev->agp->acquired || !drm_agp.acquire) return -EINVAL;
+ if ((retcode = (*drm_agp.acquire)())) return retcode;
+ dev->agp->acquired = 1;
+ return 0;
+}
+
+int drm_agp_release(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+
+ if (!dev->agp->acquired || !drm_agp.release) return -EINVAL;
+ (*drm_agp.release)();
+ dev->agp->acquired = 0;
+ return 0;
+
+}
+
+int drm_agp_enable(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_agp_mode_t mode;
+
+ if (!dev->agp->acquired || !drm_agp.enable) return -EINVAL;
+
+ copy_from_user_ret(&mode, (drm_agp_mode_t *)arg, sizeof(mode),
+ -EFAULT);
+
+ dev->agp->mode = mode.mode;
+ (*drm_agp.enable)(mode.mode);
+ dev->agp->base = dev->agp->agp_info.aper_base;
+ dev->agp->enabled = 1;
+ return 0;
+}
+
+int drm_agp_alloc(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_agp_buffer_t request;
+ drm_agp_mem_t *entry;
+ agp_memory *memory;
+ unsigned long pages;
+ u32 type;
+ if (!dev->agp->acquired) return -EINVAL;
+ copy_from_user_ret(&request, (drm_agp_buffer_t *)arg, sizeof(request),
+ -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;
+
+ if (!(memory = drm_alloc_agp(pages, type))) {
+ drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
+ return -ENOMEM;
+ }
+
+ entry->handle = (unsigned long)memory->memory;
+ entry->memory = memory;
+ entry->bound = 0;
+ entry->pages = pages;
+ entry->prev = NULL;
+ entry->next = dev->agp->memory;
+ if (dev->agp->memory) dev->agp->memory->prev = entry;
+ dev->agp->memory = entry;
+
+ request.handle = entry->handle;
+ request.physical = memory->physical;
+
+ if (copy_to_user((drm_agp_buffer_t *)arg, &request, sizeof(request))) {
+ dev->agp->memory = entry->next;
+ dev->agp->memory->prev = NULL;
+ drm_free_agp(memory, pages);
+ drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
+ return -EFAULT;
+ }
+ return 0;
+}
+
+static drm_agp_mem_t *drm_agp_lookup_entry(drm_device_t *dev,
+ unsigned long handle)
+{
+ drm_agp_mem_t *entry;
+
+ for (entry = dev->agp->memory; entry; entry = entry->next) {
+ if (entry->handle == handle) return entry;
+ }
+ return NULL;
+}
+
+int drm_agp_unbind(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_agp_binding_t request;
+ drm_agp_mem_t *entry;
+
+ if (!dev->agp->acquired) return -EINVAL;
+ copy_from_user_ret(&request, (drm_agp_binding_t *)arg, sizeof(request),
+ -EFAULT);
+ if (!(entry = drm_agp_lookup_entry(dev, request.handle)))
+ return -EINVAL;
+ if (!entry->bound) return -EINVAL;
+ return drm_unbind_agp(entry->memory);
+}
+
+int drm_agp_bind(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_agp_binding_t request;
+ drm_agp_mem_t *entry;
+ int retcode;
+ int page;
+
+ if (!dev->agp->acquired || !drm_agp.bind_memory) return -EINVAL;
+ copy_from_user_ret(&request, (drm_agp_binding_t *)arg, sizeof(request),
+ -EFAULT);
+ if (!(entry = drm_agp_lookup_entry(dev, request.handle)))
+ return -EINVAL;
+ if (entry->bound) return -EINVAL;
+ page = (request.offset + PAGE_SIZE - 1) / PAGE_SIZE;
+ if ((retcode = drm_bind_agp(entry->memory, page))) return retcode;
+ entry->bound = dev->agp->base + (page << PAGE_SHIFT);
+ DRM_DEBUG("base = 0x%lx entry->bound = 0x%lx\n",
+ dev->agp->base, entry->bound);
+ return 0;
+}
+
+int drm_agp_free(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_agp_buffer_t request;
+ drm_agp_mem_t *entry;
+
+ if (!dev->agp->acquired) return -EINVAL;
+ copy_from_user_ret(&request, (drm_agp_buffer_t *)arg, sizeof(request),
+ -EFAULT);
+ if (!(entry = drm_agp_lookup_entry(dev, request.handle)))
+ return -EINVAL;
+ if (entry->bound) drm_unbind_agp(entry->memory);
+
+ if (entry->prev) entry->prev->next = entry->next;
+ else dev->agp->memory = entry->next;
+ if (entry->next) entry->next->prev = entry->prev;
+ drm_free_agp(entry->memory, entry->pages);
+ drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
+ return 0;
+}
+
+drm_agp_head_t *drm_agp_init(void)
+{
+ drm_agp_fill_t *fill;
+ drm_agp_head_t *head = NULL;
+ int agp_available = 1;
+
+ for (fill = &drm_agp_fill[0]; fill->name; fill++) {
+ char *n = (char *)fill->name;
+ *fill->f = (drm_agp_func_u)get_module_symbol(NULL, n);
+ DRM_DEBUG("%s resolves to 0x%08lx\n", n, (*fill->f).address);
+ if (!(*fill->f).address) agp_available = 0;
+ }
+
+ DRM_DEBUG("agp_available = %d\n", agp_available);
+
+ if (agp_available) {
+ if (!(head = drm_alloc(sizeof(*head), DRM_MEM_AGPLISTS)))
+ return NULL;
+ memset((void *)head, 0, sizeof(*head));
+ (*drm_agp.copy_info)(&head->agp_info);
+ head->memory = NULL;
+ switch (head->agp_info.chipset) {
+ case INTEL_GENERIC: head->chipset = "Intel"; break;
+ case INTEL_LX: head->chipset = "Intel 440LX"; break;
+ case INTEL_BX: head->chipset = "Intel 440BX"; break;
+ case INTEL_GX: head->chipset = "Intel 440GX"; break;
+ case INTEL_I810: head->chipset = "Intel i810"; break;
+ case VIA_GENERIC: head->chipset = "VIA"; break;
+ case VIA_VP3: head->chipset = "VIA VP3"; break;
+ case VIA_MVP3: head->chipset = "VIA MVP3"; break;
+ case VIA_APOLLO_PRO: head->chipset = "VIA Apollo Pro"; break;
+ case SIS_GENERIC: head->chipset = "SiS"; break;
+ case AMD_GENERIC: head->chipset = "AMD"; break;
+ case AMD_IRONGATE: head->chipset = "AMD Irongate"; break;
+ case ALI_GENERIC: head->chipset = "ALi"; break;
+ case ALI_M1541: head->chipset = "ALi M1541"; break;
+ default:
+ }
+ DRM_INFO("AGP %d.%d on %s @ 0x%08lx %dMB\n",
+ head->agp_info.version.major,
+ head->agp_info.version.minor,
+ head->chipset,
+ head->agp_info.aper_base,
+ head->agp_info.aper_size);
+ }
+ return head;
+}
diff -urN linux.clean/drivers/char/drm/auth.c linux/drivers/char/drm/auth.c
--- linux.clean/drivers/char/drm/auth.c Tue Mar 14 12:27:31 2000
+++ linux/drivers/char/drm/auth.c Sat Jul 15 11:30:48 2000
@@ -2,6 +2,7 @@
  * Created: Tue Feb 2 08:37:54 1999 by faith@precisioninsight.com
  *
  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
  * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -44,7 +45,6 @@
 
         down(&dev->struct_sem);
         for (pt = dev->magiclist[hash].head; pt; pt = pt->next) {
- if (pt->priv->authenticated) continue;
                 if (pt->magic == magic) {
                         retval = pt->priv;
                         break;
diff -urN linux.clean/drivers/char/drm/bufs.c linux/drivers/char/drm/bufs.c
--- linux.clean/drivers/char/drm/bufs.c Wed Jun 21 13:10:02 2000
+++ linux/drivers/char/drm/bufs.c Sat Jul 15 14:46:21 2000
@@ -2,6 +2,7 @@
  * Created: Tue Feb 2 08:37:54 1999 by faith@precisioninsight.com
  *
  * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
  * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -105,6 +106,11 @@
                         dev->lock.hw_lock = map->handle; /* Pointer to lock */
                 }
                 break;
+#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+ case _DRM_AGP:
+ map->offset = map->offset + dev->agp->base;
+ break;
+#endif
         default:
                 drm_free(map, sizeof(*map), DRM_MEM_MAPS);
                 return -EINVAL;
@@ -175,7 +181,7 @@
         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;
 
@@ -480,10 +486,8 @@
                            -EFAULT);
 
         if (request.count >= dma->buf_count) {
- 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 */
                         retcode = (signed long)virtual;
diff -urN linux.clean/drivers/char/drm/context.c linux/drivers/char/drm/context.c
--- linux.clean/drivers/char/drm/context.c Tue Mar 14 12:27:31 2000
+++ linux/drivers/char/drm/context.c Sat Jul 15 11:40:26 2000
@@ -2,6 +2,7 @@
  * Created: Tue Feb 2 08:37:54 1999 by faith@precisioninsight.com
  *
  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
  * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
diff -urN linux.clean/drivers/char/drm/ctxbitmap.c linux/drivers/char/drm/ctxbitmap.c
--- linux.clean/drivers/char/drm/ctxbitmap.c Wed Dec 31 19:00:00 1969
+++ linux/drivers/char/drm/ctxbitmap.c Sat Jul 15 12:52:13 2000
@@ -0,0 +1,85 @@
+/* ctxbitmap.c -- Context bitmap management -*- linux-c -*-
+ * Created: Thu Jan 6 03:56:42 2000 by jhartmann@precisioninsight.com
+ *
+ * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Jeff Hartmann <jhartmann@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+void drm_ctxbitmap_free(drm_device_t *dev, int ctx_handle)
+{
+ if (ctx_handle < 0) goto failed;
+
+ if (ctx_handle < DRM_MAX_CTXBITMAP) {
+ clear_bit(ctx_handle, dev->ctx_bitmap);
+ return;
+ }
+failed:
+ DRM_ERROR("Attempt to free invalid context handle: %d\n",
+ ctx_handle);
+ return;
+}
+
+int drm_ctxbitmap_next(drm_device_t *dev)
+{
+ int bit;
+
+ bit = find_first_zero_bit(dev->ctx_bitmap, DRM_MAX_CTXBITMAP);
+ if (bit < DRM_MAX_CTXBITMAP) {
+ set_bit(bit, dev->ctx_bitmap);
+ DRM_DEBUG("drm_ctxbitmap_next bit : %d\n", bit);
+ return bit;
+ }
+ return -1;
+}
+
+int drm_ctxbitmap_init(drm_device_t *dev)
+{
+ int i;
+ int temp;
+
+ dev->ctx_bitmap = (unsigned long *) drm_alloc(PAGE_SIZE,
+ DRM_MEM_CTXBITMAP);
+ if(dev->ctx_bitmap == NULL) {
+ return -ENOMEM;
+ }
+ memset((void *) dev->ctx_bitmap, 0, PAGE_SIZE);
+ for(i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
+ temp = drm_ctxbitmap_next(dev);
+ DRM_DEBUG("drm_ctxbitmap_init : %d\n", temp);
+ }
+
+ return 0;
+}
+
+void drm_ctxbitmap_cleanup(drm_device_t *dev)
+{
+ drm_free((void *)dev->ctx_bitmap, PAGE_SIZE,
+ DRM_MEM_CTXBITMAP);
+}
+
diff -urN linux.clean/drivers/char/drm/dma.c linux/drivers/char/drm/dma.c
--- linux.clean/drivers/char/drm/dma.c Tue Mar 14 12:27:31 2000
+++ linux/drivers/char/drm/dma.c Sat Jul 15 11:44:22 2000
@@ -2,6 +2,7 @@
  * Created: Fri Mar 19 14:30:16 1999 by faith@precisioninsight.com
  *
  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
  * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -63,17 +64,26 @@
                                                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
                                  * 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);
+ }
+ }
         
         if (dma->buflist) {
                 drm_free(dma->buflist,
diff -urN linux.clean/drivers/char/drm/drawable.c linux/drivers/char/drm/drawable.c
--- linux.clean/drivers/char/drm/drawable.c Tue Mar 14 12:27:31 2000
+++ linux/drivers/char/drm/drawable.c Sat Jul 15 11:44:48 2000
@@ -2,6 +2,7 @@
  * Created: Tue Feb 2 08:37:54 1999 by faith@precisioninsight.com
  *
  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
  * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
diff -urN linux.clean/drivers/char/drm/drm.h linux/drivers/char/drm/drm.h
--- linux.clean/drivers/char/drm/drm.h Tue Mar 14 12:27:31 2000
+++ linux/drivers/char/drm/drm.h Sat Jul 15 13:06:51 2000
@@ -2,6 +2,7 @@
  * Created: Mon Jan 4 10:05:05 1999 by faith@precisioninsight.com
  *
  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
  * All rights reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -61,6 +62,12 @@
 typedef unsigned int drm_drawable_t;
 typedef unsigned int drm_magic_t;
 
+typedef struct drm_clip_rect {
+ unsigned short x1;
+ unsigned short y1;
+ unsigned short x2;
+ unsigned short y2;
+} drm_clip_rect_t;
 
 typedef struct drm_version {
         int version_major; /* Major version */
@@ -101,7 +108,8 @@
 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 support */
 } drm_map_type_t;
 
 typedef enum drm_map_flags {
@@ -165,8 +173,11 @@
         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 +248,39 @@
         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)
@@ -247,7 +291,7 @@
 
 #define DRM_IOCTL_VERSION DRM_IOWR(0x00, drm_version_t)
 #define DRM_IOCTL_GET_UNIQUE DRM_IOWR(0x01, drm_unique_t)
-#define DRM_IOCTL_GET_MAGIC DRM_IOW( 0x02, drm_auth_t)
+#define DRM_IOCTL_GET_MAGIC DRM_IOR( 0x02, drm_auth_t)
 #define DRM_IOCTL_IRQ_BUSID DRM_IOWR(0x03, drm_irq_busid_t)
 
 #define DRM_IOCTL_SET_UNIQUE DRM_IOW( 0x10, drm_unique_t)
@@ -275,5 +319,14 @@
 #define DRM_IOCTL_LOCK DRM_IOW( 0x2a, drm_lock_t)
 #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_IOW( 0x32, drm_agp_mode_t)
+#define DRM_IOCTL_AGP_INFO DRM_IOR( 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_IOW( 0x36, drm_agp_binding_t)
+#define DRM_IOCTL_AGP_UNBIND DRM_IOW( 0x37, drm_agp_binding_t)
 
 #endif
diff -urN linux.clean/drivers/char/drm/drmP.h linux/drivers/char/drm/drmP.h
--- linux.clean/drivers/char/drm/drmP.h Mon Jul 10 17:22:24 2000
+++ linux/drivers/char/drm/drmP.h Sat Jul 15 16:59:42 2000
@@ -2,6 +2,7 @@
  * Created: Mon Jan 4 10:05:05 1999 by faith@precisioninsight.com
  *
  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
  * All rights reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -49,7 +50,12 @@
 #ifdef CONFIG_MTRR
 #include <asm/mtrr.h>
 #endif
+#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+#include <linux/types.h>
+#include <linux/agp_backend.h>
+#endif
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
+#include <linux/tqueue.h>
 #include <linux/poll.h>
 #endif
 #include "drm.h"
@@ -84,6 +90,12 @@
 #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 */
@@ -103,11 +115,7 @@
 #endif
 
                                 /* vm_offset changed to vm_pgoff in 2.3.25 */
-#if LINUX_VERSION_CODE < 0x020319
-#define VM_OFFSET(vma) ((vma)->vm_offset)
-#else
 #define VM_OFFSET(vma) ((vma)->vm_pgoff << PAGE_SHIFT)
-#endif
 
                                 /* *_nopage return values defined in 2.3.26 */
 #ifndef NOPAGE_SIGBUS
@@ -230,6 +238,7 @@
         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 */
@@ -245,12 +254,16 @@
                 DRM_LIST_PRIO = 4,
                 DRM_LIST_RECLAIM = 5
         } list; /* Which list we're on */
+
 #if DRM_DMA_HISTOGRAM
         cycles_t time_queued; /* Queued to kernel DMA queue */
         cycles_t time_dispatched; /* Dispatched to hardware */
         cycles_t time_completed; /* Completed by hardware */
         cycles_t time_freed; /* Back on freelist */
 #endif
+
+ int dev_priv_size; /* Size of buffer private stoarge */
+ void *dev_private; /* Per-buffer private storage */
 } drm_buf_t;
 
 #if DRM_DMA_HISTOGRAM
@@ -371,6 +384,9 @@
         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 */
@@ -379,6 +395,41 @@
         wait_queue_head_t waiting; /* Processes waiting on free bufs */
 } drm_device_dma_t;
 
+#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+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 */
@@ -457,6 +508,12 @@
         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 */
+
+#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+ drm_agp_head_t *agp;
+#endif
+ unsigned long *ctx_bitmap;
+ void *dev_private;
 } drm_device_t;
 
 
@@ -529,6 +586,14 @@
 extern void *drm_ioremap(unsigned long offset, unsigned long size);
 extern void drm_ioremapfree(void *pt, unsigned long size);
 
+#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+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,
@@ -638,5 +703,32 @@
                                        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);
+
+#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+ /* 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 -urN linux.clean/drivers/char/drm/fops.c linux/drivers/char/drm/fops.c
--- linux.clean/drivers/char/drm/fops.c Wed Jun 21 13:10:02 2000
+++ linux/drivers/char/drm/fops.c Sat Jul 15 18:41:38 2000
@@ -2,6 +2,7 @@
  * Created: Mon Jan 4 08:58:31 1999 by faith@precisioninsight.com
  *
  * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
  * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -31,6 +32,7 @@
 
 #define __NO_VERSION__
 #include "drmP.h"
+#include <linux/poll.h>
 
 /* drm_open is called whenever a process opens /dev/drm. */
 
@@ -93,7 +95,6 @@
                   current->pid, dev->device, dev->open_count);
 
         if (dev->lock.hw_lock != NULL
- && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)
             && dev->lock.pid == current->pid) {
                 DRM_ERROR("Process %d dead, freeing lock for context %d\n",
                           current->pid,
@@ -213,12 +214,7 @@
                 send -= count;
         }
 
-#if LINUX_VERSION_CODE < 0x020315
- if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO);
-#else
- /* Parameter added in 2.3.21 */
         kill_fasync(&dev->buf_async, SIGIO, POLL_IN);
-#endif
         DRM_DEBUG("waking\n");
         wake_up_interruptible(&dev->buf_readers);
         return 0;
diff -urN linux.clean/drivers/char/drm/gamma_dma.c linux/drivers/char/drm/gamma_dma.c
--- linux.clean/drivers/char/drm/gamma_dma.c Tue Mar 14 12:27:31 2000
+++ linux/drivers/char/drm/gamma_dma.c Sat Jul 15 12:05:45 2000
@@ -2,6 +2,7 @@
  * Created: Fri Mar 19 14:30:16 1999 by faith@precisioninsight.com
  *
  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
  * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -87,28 +88,45 @@
         GAMMA_WRITE(GAMMA_DMACOUNT, length / 4);
 }
 
-static inline void gamma_dma_quiescent(drm_device_t *dev)
+static inline void gamma_dma_quiescent_single(drm_device_t *dev)
 {
         while (GAMMA_READ(GAMMA_DMACOUNT))
                 ;
         while (GAMMA_READ(GAMMA_INFIFOSPACE) < 3)
                 ;
- GAMMA_WRITE(GAMMA_BROADCASTMASK, 3);
+
         GAMMA_WRITE(GAMMA_FILTERMODE, 1 << 10);
         GAMMA_WRITE(GAMMA_SYNC, 0);
         
- /* Read from first MX */
         do {
                 while (!GAMMA_READ(GAMMA_OUTFIFOWORDS))
                         ;
         } while (GAMMA_READ(GAMMA_OUTPUTFIFO) != GAMMA_SYNC_TAG);
-
+}
 
- /* Read from second MX */
- do {
- while (!GAMMA_READ(GAMMA_OUTFIFOWORDS + 0x10000))
- ;
- } while (GAMMA_READ(GAMMA_OUTPUTFIFO + 0x10000) != GAMMA_SYNC_TAG);
+static inline void gamma_dma_quiescent_dual(drm_device_t *dev)
+{
+ while (GAMMA_READ(GAMMA_DMACOUNT))
+ ;
+ while (GAMMA_READ(GAMMA_INFIFOSPACE) < 3)
+ ;
+
+ GAMMA_WRITE(GAMMA_BROADCASTMASK, 3);
+
+ GAMMA_WRITE(GAMMA_FILTERMODE, 1 << 10);
+ GAMMA_WRITE(GAMMA_SYNC, 0);
+
+ /* Read from first MX */
+ do {
+ while (!GAMMA_READ(GAMMA_OUTFIFOWORDS))
+ ;
+ } while (GAMMA_READ(GAMMA_OUTPUTFIFO) != GAMMA_SYNC_TAG);
+
+ /* Read from second MX */
+ do {
+ while (!GAMMA_READ(GAMMA_OUTFIFOWORDS + 0x10000))
+ ;
+ } while (GAMMA_READ(GAMMA_OUTPUTFIFO + 0x10000) != GAMMA_SYNC_TAG);
 }
 
 static inline void gamma_dma_ready(drm_device_t *dev)
@@ -788,8 +806,13 @@
         if (!ret) {
                 if (lock.flags & _DRM_LOCK_READY)
                         gamma_dma_ready(dev);
- if (lock.flags & _DRM_LOCK_QUIESCENT)
- gamma_dma_quiescent(dev);
+ if (lock.flags & _DRM_LOCK_QUIESCENT) {
+ if (gamma_found() == 1) {
+ gamma_dma_quiescent_single(dev);
+ } else {
+ gamma_dma_quiescent_dual(dev);
+ }
+ }
         }
         DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock");
 
diff -urN linux.clean/drivers/char/drm/gamma_drv.c linux/drivers/char/drm/gamma_drv.c
--- linux.clean/drivers/char/drm/gamma_drv.c Sat Jul 15 10:44:13 2000
+++ linux/drivers/char/drm/gamma_drv.c Sat Jul 15 14:48:10 2000
@@ -2,6 +2,7 @@
  * Created: Mon Jan 4 08:58:31 1999 by faith@precisioninsight.com
  *
  * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
  * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -36,6 +37,13 @@
 EXPORT_SYMBOL(gamma_init);
 EXPORT_SYMBOL(gamma_cleanup);
 
+#ifndef PCI_DEVICE_ID_3DLABS_GAMMA
+#define PCI_DEVICE_ID_3DLABS_GAMMA 0x0008
+#endif
+#ifndef PCI_DEVICE_ID_3DLABS_MX
+#define PCI_DEVICE_ID_3DLABS_MX 0x0006
+#endif
+
 #define GAMMA_NAME "gamma"
 #define GAMMA_DESC "3dlabs GMX 2000"
 #define GAMMA_DATE "19990830"
@@ -46,7 +54,6 @@
 static drm_device_t gamma_device;
 
 static struct file_operations gamma_fops = {
- owner: THIS_MODULE,
         open: gamma_open,
         flush: drm_flush,
         release: gamma_release,
@@ -101,10 +108,13 @@
 int init_module(void);
 void cleanup_module(void);
 static char *gamma = NULL;
+static int devices = 0;
 
 MODULE_AUTHOR("Precision Insight, Inc., Cedar Park, Texas.");
 MODULE_DESCRIPTION("3dlabs GMX 2000");
 MODULE_PARM(gamma, "s");
+MODULE_PARM(devices, "i");
+MODULE_PARM_DESC(devices, "devices=x, where x is the number of MX chips on your card\n");
 
 /* init_module is called when insmod is used to load the module */
 
@@ -274,6 +284,12 @@
                                                - PAGE_SHIFT,
                                                DRM_MEM_SAREA);
                                 break;
+#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+ case _DRM_AGP:
+ /* Do nothing here, because this is all
+ handled in the AGP/GART driver. */
+ break;
+#endif
                         }
                         drm_free(map, sizeof(*map), DRM_MEM_MAPS);
                 }
@@ -313,6 +329,34 @@
         return 0;
 }
 
+int gamma_found(void)
+{
+ return devices;
+}
+
+int gamma_find_devices(void)
+{
+ struct pci_dev *d = NULL, *one = NULL, *two = NULL;
+
+ d = pci_find_device(PCI_VENDOR_ID_3DLABS,PCI_DEVICE_ID_3DLABS_GAMMA,d);
+ if (!d) return 0;
+
+ one = pci_find_device(PCI_VENDOR_ID_3DLABS,PCI_DEVICE_ID_3DLABS_MX,d);
+ if (!one) return 0;
+
+ /* Make sure it's on the same card, if not - no MX's found */
+ if (PCI_SLOT(d->devfn) != PCI_SLOT(one->devfn)) return 0;
+
+ two = pci_find_device(PCI_VENDOR_ID_3DLABS,PCI_DEVICE_ID_3DLABS_MX,one);
+ if (!two) return 1;
+
+ /* Make sure it's on the same card, if not - only 1 MX found */
+ if (PCI_SLOT(d->devfn) != PCI_SLOT(two->devfn)) return 1;
+
+ /* Two MX's found - we don't currently support more than 2 */
+ return 2;
+}
+
 /* gamma_init is called via init_module at module load time, or via
  * linux/init/main.c (this is not currently supported). */
 
@@ -330,6 +374,8 @@
 #ifdef MODULE
         drm_parse_options(gamma);
 #endif
+ devices = gamma_find_devices();
+ if (devices == 0) return -1;
 
         if ((retcode = misc_register(&gamma_misc))) {
                 DRM_ERROR("Cannot register \"%s\"\n", GAMMA_NAME);
@@ -347,7 +393,8 @@
                  GAMMA_MINOR,
                  GAMMA_PATCHLEVEL,
                  GAMMA_DATE,
- gamma_misc.minor);
+ gamma_misc.minor,
+ devices);
         
         return 0;
 }
@@ -410,6 +457,7 @@
         
         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++) {
@@ -427,10 +475,9 @@
         drm_device_t *dev;
         int retcode = 0;
 
- lock_kernel();
- dev = priv->dev;
         DRM_DEBUG("open_count = %d\n", dev->open_count);
         if (!(retcode = drm_release(inode, filp))) {
+ MOD_INC_USE_COUNT;
                 atomic_inc(&dev->total_close);
                 spin_lock(&dev->count_lock);
                 if (!--dev->open_count) {
@@ -439,17 +486,13 @@
                                           atomic_read(&dev->ioctl_count),
                                           dev->blocked);
                                 spin_unlock(&dev->count_lock);
- unlock_kernel();
                                 return -EBUSY;
                         }
                         spin_unlock(&dev->count_lock);
- retcode = gamma_takedown(dev);
- unlock_kernel();
- return retcode;
+ return gamma_takedown(dev);
                 }
                 spin_unlock(&dev->count_lock);
         }
- unlock_kernel();
         return retcode;
 }
 
diff -urN linux.clean/drivers/char/drm/gamma_drv.h linux/drivers/char/drm/gamma_drv.h
--- linux.clean/drivers/char/drm/gamma_drv.h Tue Mar 14 12:27:31 2000
+++ linux/drivers/char/drm/gamma_drv.h Sat Jul 15 12:14:45 2000
@@ -2,6 +2,7 @@
  * Created: Mon Jan 4 10:05:05 1999 by faith@precisioninsight.com
  *
  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
  * All rights reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -53,5 +54,7 @@
 extern int gamma_irq_uninstall(drm_device_t *dev);
 extern int gamma_control(struct inode *inode, struct file *filp,
                           unsigned int cmd, unsigned long arg);
+extern int gamma_find_devices(void);
+extern int gamma_found(void);
 
 #endif
diff -urN linux.clean/drivers/char/drm/init.c linux/drivers/char/drm/init.c
--- linux.clean/drivers/char/drm/init.c Wed Jun 21 13:10:02 2000
+++ linux/drivers/char/drm/init.c Sat Jul 15 12:16:10 2000
@@ -2,6 +2,7 @@
  * Created: Mon Jan 4 08:58:31 1999 by faith@precisioninsight.com
  *
  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
  * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
diff -urN linux.clean/drivers/char/drm/ioctl.c linux/drivers/char/drm/ioctl.c
--- linux.clean/drivers/char/drm/ioctl.c Tue Mar 14 12:27:31 2000
+++ linux/drivers/char/drm/ioctl.c Sat Jul 15 12:16:50 2000
@@ -2,6 +2,7 @@
  * Created: Fri Jan 8 09:01:26 1999 by faith@precisioninsight.com
  *
  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
  * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
diff -urN linux.clean/drivers/char/drm/lists.c linux/drivers/char/drm/lists.c
--- linux.clean/drivers/char/drm/lists.c Tue Mar 14 12:27:31 2000
+++ linux/drivers/char/drm/lists.c Sat Jul 15 12:18:23 2000
@@ -2,6 +2,7 @@
  * Created: Mon Apr 19 20:54:22 1999 by faith@precisioninsight.com
  *
  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
  * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
diff -urN linux.clean/drivers/char/drm/lock.c linux/drivers/char/drm/lock.c
--- linux.clean/drivers/char/drm/lock.c Tue Mar 14 12:27:31 2000
+++ linux/drivers/char/drm/lock.c Sat Jul 15 12:19:27 2000
@@ -2,6 +2,7 @@
  * Created: Tue Feb 2 08:37:54 1999 by faith@precisioninsight.com
  *
  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
  * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
diff -urN linux.clean/drivers/char/drm/memory.c linux/drivers/char/drm/memory.c
--- linux.clean/drivers/char/drm/memory.c Tue Mar 14 12:27:31 2000
+++ linux/drivers/char/drm/memory.c Sat Jul 15 14:48:29 2000
@@ -2,6 +2,7 @@
  * Created: Thu Feb 4 14:00:34 1999 by faith@precisioninsight.com
  *
  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
  * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -59,6 +60,10 @@
         [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 */
 };
 
@@ -76,12 +81,7 @@
         }
         
         si_meminfo(&si);
-#if LINUX_VERSION_CODE < 0x020317
- /* Changed to page count in 2.3.23 */
- drm_ram_available = si.totalram >> PAGE_SHIFT;
-#else
- drm_ram_available = si.totalram;
-#endif
+ drm_ram_available = si.totalram;
         drm_ram_used = 0;
 }
 
@@ -324,3 +324,121 @@
                               free_count, alloc_count);
         }
 }
+
+#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+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 -urN linux.clean/drivers/char/drm/proc.c linux/drivers/char/drm/proc.c
--- linux.clean/drivers/char/drm/proc.c Thu Jul 6 01:15:27 2000
+++ linux/drivers/char/drm/proc.c Sat Jul 15 17:50:35 2000
@@ -2,6 +2,7 @@
  * Created: Mon Jan 11 09:48:47 1999 by faith@precisioninsight.com
  *
  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
  * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -25,7 +26,6 @@
  *
  * Authors:
  * Rickard E. (Rik) Faith <faith@precisioninsight.com>
- *
  */
 
 #define __NO_VERSION__
@@ -164,7 +164,10 @@
 {
         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 @@
                        "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,
@@ -397,6 +400,7 @@
                                pgprot & _PAGE_GLOBAL ? 'g' : 'l' );
 #endif
                 DRM_PROC_PRINT("\n");
+#if 0
                 for (i = vma->vm_start; i < vma->vm_end; i += PAGE_SIZE) {
                         pgd = pgd_offset(vma->vm_mm, i);
                         pmd = pmd_offset(pgd, i);
@@ -417,6 +421,7 @@
                                 DRM_PROC_PRINT(" 0x%08lx\n", i);
                         }
                 }
+#endif
         }
         
         return len;
diff -urN linux.clean/drivers/char/drm/tdfx_context.c linux/drivers/char/drm/tdfx_context.c
--- linux.clean/drivers/char/drm/tdfx_context.c Tue Mar 14 12:27:31 2000
+++ linux/drivers/char/drm/tdfx_context.c Sat Jul 15 12:31:19 2000
@@ -2,6 +2,7 @@
  * Created: Thu Oct 7 10:50:22 1999 by faith@precisioninsight.com
  *
  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
  * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -25,6 +26,7 @@
  *
  * Authors:
  * Rickard E. (Rik) Faith <faith@precisioninsight.com>
+ * Daryll Strauss <daryll@valinux.com>
  *
  */
 
@@ -38,9 +40,7 @@
 
 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 +137,12 @@
                 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;
 }
diff -urN linux.clean/drivers/char/drm/tdfx_drv.c linux/drivers/char/drm/tdfx_drv.c
--- linux.clean/drivers/char/drm/tdfx_drv.c Sat Jul 15 10:44:13 2000
+++ linux/drivers/char/drm/tdfx_drv.c Sat Jul 15 18:42:08 2000
@@ -2,6 +2,7 @@
  * Created: Thu Oct 7 10:38:32 1999 by faith@precisioninsight.com
  *
  * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
  * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -30,23 +31,23 @@
  */
 
 #include <linux/config.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
+#define EXPORT_SYMTAB
 #include "drmP.h"
 #include "tdfx_drv.h"
+EXPORT_SYMBOL(tdfx_init);
+EXPORT_SYMBOL(tdfx_cleanup);
 
 #define TDFX_NAME "tdfx"
 #define TDFX_DESC "tdfx"
 #define TDFX_DATE "19991009"
-#define TDFX_MAJOR 0
+#define TDFX_MAJOR 1
 #define TDFX_MINOR 0
-#define TDFX_PATCHLEVEL 1
+#define TDFX_PATCHLEVEL 0
 
 static drm_device_t tdfx_device;
 drm_ctx_t tdfx_res_ctx;
 
 static struct file_operations tdfx_fops = {
- owner: THIS_MODULE,
         open: tdfx_open,
         flush: drm_flush,
         release: tdfx_release,
@@ -87,17 +88,62 @@
         [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 },
+#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+ [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)
 
 #ifdef MODULE
+int init_module(void);
+void cleanup_module(void);
 static char *tdfx = NULL;
-#endif
 
 MODULE_AUTHOR("Precision Insight, Inc., Cedar Park, Texas.");
 MODULE_DESCRIPTION("tdfx");
 MODULE_PARM(tdfx, "s");
 
+/* init_module is called when insmod is used to load the module */
+
+int init_module(void)
+{
+ return tdfx_init();
+}
+
+/* cleanup_module is called when rmmod is used to unload the module */
+
+void cleanup_module(void)
+{
+ tdfx_cleanup();
+}
+#endif
+
+#ifndef MODULE
+/* tdfx_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 tdfx_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 tdfx_setup(drm_device_t *dev)
 {
         int i;
@@ -195,7 +241,24 @@
                 }
                 dev->magiclist[i].head = dev->magiclist[i].tail = NULL;
         }
-
+#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+ /* 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) {
@@ -229,6 +292,10 @@
                                                - 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);
                 }
@@ -276,6 +343,16 @@
 
         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,
@@ -302,6 +379,7 @@
         } else {
                 DRM_INFO("Module unloaded\n");
         }
+ drm_ctxbitmap_cleanup(dev);
         tdfx_takedown(dev);
 }
 
@@ -346,6 +424,7 @@
         
         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++) {
@@ -363,10 +442,9 @@
         drm_device_t *dev;
         int retcode = 0;
 
- lock_kernel();
- dev = priv->dev;
         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) {
@@ -375,17 +453,13 @@
                                           atomic_read(&dev->ioctl_count),
                                           dev->blocked);
                                 spin_unlock(&dev->count_lock);
- unlock_kernel();
                                 return -EBUSY;
                         }
                         spin_unlock(&dev->count_lock);
- retcode = tdfx_takedown(dev);
- unlock_kernel();
- return retcode;
+ return tdfx_takedown(dev);
                 }
                 spin_unlock(&dev->count_lock);
         }
- unlock_kernel();
         return retcode;
 }
 
@@ -500,7 +574,9 @@
                                 /* Contention */
                         atomic_inc(&dev->total_sleeps);
                         current->state = TASK_INTERRUPTIBLE;
+#if 1
                         current->policy |= SCHED_YIELD;
+#endif
                         schedule();
                         if (signal_pending(current)) {
                                 ret = -ERESTARTSYS;
@@ -549,11 +625,20 @@
                 }
         }
 
+#if 0
+ DRM_ERROR("pid = %5d, old counter = %5ld\n",
+ current->pid, current->counter);
+#endif
         if (lock.context != tdfx_res_ctx.handle) {
                 current->counter = 5;
                 current->nice = 0;
         }
-
+#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
@@ -593,29 +678,21 @@
                         DRM_ERROR("\n");
                 }
         }
+
+#if 0
+ current->policy |= SCHED_YIELD;
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(1000);
+#endif
         
         if (lock.context != tdfx_res_ctx.handle) {
                 current->counter = 5;
                 current->nice = 0;
         }
+#if 0
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(10);
+#endif
 
         return 0;
 }
-
-module_init(tdfx_init);
-module_exit(tdfx_cleanup);
-
-#ifndef MODULE
-/*
- * tdfx_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_options.
- */
-static int __init tdfx_options(char *str)
-{
- drm_parse_options(str);
- return 1;
-}
-
-__setup("tdfx=", tdfx_options);
-#endif
diff -urN linux.clean/drivers/char/drm/tdfx_drv.h linux/drivers/char/drm/tdfx_drv.h
--- linux.clean/drivers/char/drm/tdfx_drv.h Tue Mar 14 12:27:31 2000
+++ linux/drivers/char/drm/tdfx_drv.h Sat Jul 15 12:43:53 2000
@@ -2,6 +2,7 @@
  * Created: Thu Oct 7 10:40:04 1999 by faith@precisioninsight.com
  *
  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
  * All rights reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
diff -urN linux.clean/drivers/char/drm/vm.c linux/drivers/char/drm/vm.c
--- linux.clean/drivers/char/drm/vm.c Sat Jul 15 10:44:13 2000
+++ linux/drivers/char/drm/vm.c Sat Jul 15 18:36:28 2000
@@ -2,6 +2,7 @@
  * Created: Mon Jan 4 08:58:31 1999 by faith@precisioninsight.com
  *
  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
  * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -65,16 +66,9 @@
         return NOPAGE_SIGBUS; /* Disallow mremap */
 }
 
-#if LINUX_VERSION_CODE < 0x020317
-unsigned long drm_vm_shm_nopage(struct vm_area_struct *vma,
- unsigned long address,
- int write_access)
-#else
- /* Return type changed in 2.3.23 */
 struct page *drm_vm_shm_nopage(struct vm_area_struct *vma,
                                unsigned long address,
                                int write_access)
-#endif
 {
         drm_file_t *priv = vma->vm_file->private_data;
         drm_device_t *dev = priv->dev;
@@ -91,23 +85,12 @@
         atomic_inc(&mem_map[MAP_NR(physical)].count); /* Dec. by kernel */
 
         DRM_DEBUG("0x%08lx (page %lu) => 0x%08lx\n", address, page, physical);
-#if LINUX_VERSION_CODE < 0x020317
- return physical;
-#else
         return mem_map + MAP_NR(physical);
-#endif
 }
 
-#if LINUX_VERSION_CODE < 0x020317
-unsigned long drm_vm_dma_nopage(struct vm_area_struct *vma,
- unsigned long address,
- int write_access)
-#else
- /* Return type changed in 2.3.23 */
 struct page *drm_vm_dma_nopage(struct vm_area_struct *vma,
                                unsigned long address,
                                int write_access)
-#endif
 {
         drm_file_t *priv = vma->vm_file->private_data;
         drm_device_t *dev = priv->dev;
@@ -126,11 +109,7 @@
         atomic_inc(&mem_map[MAP_NR(physical)].count); /* Dec. by kernel */
 
         DRM_DEBUG("0x%08lx (page %lu) => 0x%08lx\n", address, page, physical);
-#if LINUX_VERSION_CODE < 0x020317
- return physical;
-#else
         return mem_map + MAP_NR(physical);
-#endif
 }
 
 void drm_vm_open(struct vm_area_struct *vma)
@@ -144,6 +123,7 @@
         DRM_DEBUG("0x%08lx,0x%08lx\n",
                   vma->vm_start, vma->vm_end - vma->vm_start);
         atomic_inc(&dev->vma_count);
+ MOD_INC_USE_COUNT;
 
 #if DRM_DEBUG_CODE
         vma_entry = drm_alloc(sizeof(*vma_entry), DRM_MEM_VMAS);
@@ -168,6 +148,7 @@
 
         DRM_DEBUG("0x%08lx,0x%08lx\n",
                   vma->vm_start, vma->vm_end - vma->vm_start);
+ MOD_DEC_USE_COUNT;
         atomic_dec(&dev->vma_count);
 
 #if DRM_DEBUG_CODE
@@ -203,11 +184,6 @@
         vma->vm_ops = &drm_vm_dma_ops;
         vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */
         
-#if LINUX_VERSION_CODE < 0x020203 /* KERNEL_VERSION(2,2,3) */
- /* In Linux 2.2.3 and above, this is
- handled in do_mmap() in mm/mmap.c. */
- ++filp->f_count;
-#endif
         vma->vm_file = filp; /* Needed for drm_vm_open() */
         drm_vm_open(vma);
         return 0;
@@ -244,10 +220,23 @@
                                 /* Check for valid size. */
         if (map->size != vma->vm_end - vma->vm_start) return -EINVAL;
         
+ if (!capable(CAP_SYS_ADMIN) && (map->flags & _DRM_READ_ONLY)) {
+ vma->vm_flags &= VM_MAYWRITE;
+#if defined(__i386__)
+ pgprot_val(vma->vm_page_prot) &= ~_PAGE_RW;
+#else
+ /* Ye gads this is ugly. With more thought
+ we could move this up higher and use
+ `protection_map' instead. */
+ vma->vm_page_prot = __pgprot(pte_val(pte_wrprotect(
+ __pte(pgprot_val(vma->vm_page_prot)))));
+#endif
+ }
 
         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) {
@@ -262,6 +251,10 @@
                                      vma->vm_end - vma->vm_start,
                                      vma->vm_page_prot))
                                 return -EAGAIN;
+ DRM_DEBUG(" Type = %d; start = 0x%lx, end = 0x%lx,"
+ " offset = 0x%lx\n",
+ map->type,
+ vma->vm_start, vma->vm_end, VM_OFFSET(vma));
                 vma->vm_ops = &drm_vm_ops;
                 break;
         case _DRM_SHM:
@@ -274,25 +267,8 @@
                 return -EINVAL; /* This should never happen. */
         }
         vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */
- if (map->flags & _DRM_READ_ONLY) {
-#if defined(__i386__)
- pgprot_val(vma->vm_page_prot) &= ~_PAGE_RW;
-#else
- /* Ye gads this is ugly. With more thought
- we could move this up higher and use
- `protection_map' instead. */
- vma->vm_page_prot = __pgprot(pte_val(pte_wrprotect(
- __pte(pgprot_val(vma->vm_page_prot)))));
-#endif
- }
 
-
-#if LINUX_VERSION_CODE < 0x020203 /* KERNEL_VERSION(2,2,3) */
- /* In Linux 2.2.3 and above, this is
- handled in do_mmap() in mm/mmap.c. */
- ++filp->f_count;
-#endif
- vma->vm_file = filp; /* Needed for drm_vm_open() */
- drm_vm_open(vma);
- return 0;
+ vma->vm_file = filp; /* Needed for drm_vm_open() */
+ drm_vm_open(vma);
+ return 0;
 }

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Sat Jul 15 2000 - 21:00:22 EST