summaryrefslogtreecommitdiff
path: root/bsd/drm
diff options
context:
space:
mode:
Diffstat (limited to 'bsd/drm')
-rw-r--r--bsd/drm/Makefile17
-rw-r--r--bsd/drm/agpsupport.c271
-rw-r--r--bsd/drm/auth.c168
-rw-r--r--bsd/drm/bufs.c500
-rw-r--r--bsd/drm/context.c297
-rw-r--r--bsd/drm/dma.c534
-rw-r--r--bsd/drm/drawable.c50
-rw-r--r--bsd/drm/drmstat.c418
-rw-r--r--bsd/drm/fops.c260
-rw-r--r--bsd/drm/init.c101
-rw-r--r--bsd/drm/ioctl.c120
-rw-r--r--bsd/drm/lists.c258
-rw-r--r--bsd/drm/lock.c220
-rw-r--r--bsd/drm/memory.c458
-rw-r--r--bsd/drm/proc.c568
-rw-r--r--bsd/drm/sysctl.c554
-rw-r--r--bsd/drm/vm.c104
17 files changed, 4898 insertions, 0 deletions
diff --git a/bsd/drm/Makefile b/bsd/drm/Makefile
new file mode 100644
index 00000000..6a70a5b0
--- /dev/null
+++ b/bsd/drm/Makefile
@@ -0,0 +1,17 @@
+# $FreeBSD$
+
+KMOD = drm
+SRCS = init.c memory.c auth.c context.c drawable.c bufs.c \
+ lists.c lock.c ioctl.c fops.c vm.c dma.c sysctl.c \
+ agpsupport.c
+SRCS += device_if.h bus_if.h pci_if.h
+CFLAGS += ${DEBUG_FLAGS} -I.. # -DDRM_AGP
+KERN = /usr/src/sys
+
+@:
+ ln -sf /sys @
+
+machine:
+ ln -sf /sys/i386/include machine
+
+.include "/usr/src/sys/conf/kmod.mk"
diff --git a/bsd/drm/agpsupport.c b/bsd/drm/agpsupport.c
new file mode 100644
index 00000000..53444c90
--- /dev/null
+++ b/bsd/drm/agpsupport.c
@@ -0,0 +1,271 @@
+/* agpsupport.c -- DRM support for AGP/GART backend
+ * Created: Mon Dec 13 09:56:45 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Rickard E. (Rik) Faith <faith@precisioninsight.com>
+ *
+ * $XFree86$
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+#ifdef DRM_AGP
+
+#include <pci/agpvar.h>
+
+MODULE_DEPEND(drm, agp, 1, 1, 1);
+
+int
+drm_agp_info(dev_t kdev, u_long cmd, caddr_t data,
+ int flags, struct proc *p)
+{
+ drm_device_t *dev = kdev->si_drv1;
+ struct agp_info *kern;
+ drm_agp_info_t info;
+
+ if (!dev->agp->acquired) return EINVAL;
+
+ kern = &dev->agp->info;
+ agp_get_info(dev->agp->agpdev, kern);
+ info.agp_version_major = 1;
+ info.agp_version_minor = 0;
+ info.mode = kern->ai_mode;
+ info.aperture_base = kern->ai_aperture_base;
+ info.aperture_size = kern->ai_aperture_size;
+ info.memory_allowed = kern->ai_memory_allowed;
+ info.memory_used = kern->ai_memory_used;
+ info.id_vendor = kern->ai_devid & 0xffff;
+ info.id_device = kern->ai_devid >> 16;
+
+ *(drm_agp_info_t *) data = info;
+ return 0;
+}
+
+int
+drm_agp_acquire(dev_t kdev, u_long cmd, caddr_t data,
+ int flags, struct proc *p)
+{
+ drm_device_t *dev = kdev->si_drv1;
+ int retcode;
+
+ if (dev->agp->acquired) return EINVAL;
+ retcode = agp_acquire(dev->agp->agpdev);
+ if (retcode) return retcode;
+ dev->agp->acquired = 1;
+ return 0;
+}
+
+int
+drm_agp_release(dev_t kdev, u_long cmd, caddr_t data,
+ int flags, struct proc *p)
+{
+ drm_device_t *dev = kdev->si_drv1;
+
+ if (!dev->agp->acquired) return EINVAL;
+ agp_release(dev->agp->agpdev);
+ dev->agp->acquired = 0;
+ return 0;
+
+}
+
+int
+drm_agp_enable(dev_t kdev, u_long cmd, caddr_t data,
+ int flags, struct proc *p)
+{
+ drm_device_t *dev = kdev->si_drv1;
+ drm_agp_mode_t mode;
+
+ if (!dev->agp->acquired) return EINVAL;
+
+ mode = *(drm_agp_mode_t *) data;
+
+ dev->agp->mode = mode.mode;
+ agp_enable(dev->agp->agpdev, mode.mode);
+ dev->agp->base = dev->agp->info.ai_aperture_base;
+ dev->agp->enabled = 1;
+ return 0;
+}
+
+int drm_agp_alloc(dev_t kdev, u_long cmd, caddr_t data,
+ int flags, struct proc *p)
+{
+ drm_device_t *dev = kdev->si_drv1;
+ drm_agp_buffer_t request;
+ drm_agp_mem_t *entry;
+ void *handle;
+ unsigned long pages;
+ u_int32_t type;
+ struct agp_memory_info info;
+
+ if (!dev->agp->acquired) return EINVAL;
+
+ request = *(drm_agp_buffer_t *) data;
+
+ 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 = (u_int32_t) request.type;
+
+ if (!(handle = drm_alloc_agp(pages, type))) {
+ drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
+ return ENOMEM;
+ }
+
+ entry->handle = handle;
+ 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;
+
+ agp_memory_info(dev->agp->agpdev, entry->handle, &info);
+
+ request.handle = (unsigned long) entry->handle;
+ request.physical = info.ami_physical;
+
+ *(drm_agp_buffer_t *) data = request;
+
+ return 0;
+}
+
+static drm_agp_mem_t *
+drm_agp_lookup_entry(drm_device_t *dev, void *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(dev_t kdev, u_long cmd, caddr_t data,
+ int flags, struct proc *p)
+{
+ drm_device_t *dev = kdev->si_drv1;
+ drm_agp_binding_t request;
+ drm_agp_mem_t *entry;
+
+ if (!dev->agp->acquired) return EINVAL;
+ request = *(drm_agp_binding_t *) data;
+ if (!(entry = drm_agp_lookup_entry(dev, (void *) request.handle)))
+ return EINVAL;
+ if (!entry->bound) return EINVAL;
+ return drm_unbind_agp(entry->handle);
+}
+
+int drm_agp_bind(dev_t kdev, u_long cmd, caddr_t data,
+ int flags, struct proc *p)
+{
+ drm_device_t *dev = kdev->si_drv1;
+ drm_agp_binding_t request;
+ drm_agp_mem_t *entry;
+ int retcode;
+ int page;
+
+ if (!dev->agp->acquired) return EINVAL;
+ request = *(drm_agp_binding_t *) data;
+ if (!(entry = drm_agp_lookup_entry(dev, (void *) request.handle)))
+ return EINVAL;
+ if (entry->bound) return EINVAL;
+ page = (request.offset + PAGE_SIZE - 1) / PAGE_SIZE;
+ if ((retcode = drm_bind_agp(entry->handle, page))) return retcode;
+ entry->bound = dev->agp->base + (page << PAGE_SHIFT);
+ return 0;
+}
+
+int drm_agp_free(dev_t kdev, u_long cmd, caddr_t data,
+ int flags, struct proc *p)
+{
+ drm_device_t *dev = kdev->si_drv1;
+ drm_agp_buffer_t request;
+ drm_agp_mem_t *entry;
+
+ if (!dev->agp->acquired) return EINVAL;
+ request = *(drm_agp_buffer_t *) data;
+ if (!(entry = drm_agp_lookup_entry(dev, (void*) request.handle)))
+ return EINVAL;
+ if (entry->bound) drm_unbind_agp(entry->handle);
+
+ 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->handle, entry->pages);
+ drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
+ return 0;
+}
+
+drm_agp_head_t *drm_agp_init(void)
+{
+ device_t agpdev;
+ drm_agp_head_t *head = NULL;
+ int agp_available = 1;
+
+ agpdev = agp_find_device();
+ if (!agpdev)
+ 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;
+ head->agpdev = agpdev;
+ memset((void *)head, 0, sizeof(*head));
+ agp_get_info(agpdev, &head->info);
+ head->memory = NULL;
+#if 0 /* bogus */
+ 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:
+ }
+#endif
+ DRM_INFO("AGP at 0x%08x %dMB\n",
+ head->info.ai_aperture_base,
+ head->info.ai_aperture_size >> 20);
+ }
+ return head;
+}
+
+#endif /* DRM_AGP */
diff --git a/bsd/drm/auth.c b/bsd/drm/auth.c
new file mode 100644
index 00000000..f7b3bc49
--- /dev/null
+++ b/bsd/drm/auth.c
@@ -0,0 +1,168 @@
+/* auth.c -- IOCTLs for authentication -*- c -*-
+ * Created: Tue Feb 2 08:37:54 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 11:31:48 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/auth.c,v 1.4 1999/08/30 13:05:00 faith Exp $
+ * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/auth.c,v 1.1 1999/09/25 14:37:57 dawes Exp $
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+static int drm_hash_magic(drm_magic_t magic)
+{
+ return magic & (DRM_HASH_SIZE-1);
+}
+
+static drm_file_t *drm_find_file(drm_device_t *dev, drm_magic_t magic)
+{
+ drm_file_t *retval = NULL;
+ drm_magic_entry_t *pt;
+ int hash = drm_hash_magic(magic);
+
+ lockmgr(&dev->dev_lock, LK_EXCLUSIVE, 0, curproc);
+ for (pt = dev->magiclist[hash].head; pt; pt = pt->next) {
+ if (pt->priv->authenticated) continue;
+ if (pt->magic == magic) {
+ retval = pt->priv;
+ break;
+ }
+ }
+ lockmgr(&dev->dev_lock, LK_RELEASE, 0, curproc);
+
+ return retval;
+}
+
+int drm_add_magic(drm_device_t *dev, drm_file_t *priv, drm_magic_t magic)
+{
+ int hash;
+ drm_magic_entry_t *entry;
+
+ DRM_DEBUG("%d\n", magic);
+
+ hash = drm_hash_magic(magic);
+ entry = drm_alloc(sizeof(*entry), DRM_MEM_MAGIC);
+ if (!entry) return ENOMEM;
+ entry->magic = magic;
+ entry->priv = priv;
+ entry->next = NULL;
+
+ lockmgr(&dev->dev_lock, LK_EXCLUSIVE, 0, curproc);
+ if (dev->magiclist[hash].tail) {
+ dev->magiclist[hash].tail->next = entry;
+ dev->magiclist[hash].tail = entry;
+ } else {
+ dev->magiclist[hash].head = entry;
+ dev->magiclist[hash].tail = entry;
+ }
+ lockmgr(&dev->dev_lock, LK_RELEASE, 0, curproc);
+
+ return 0;
+}
+
+int drm_remove_magic(drm_device_t *dev, drm_magic_t magic)
+{
+ drm_magic_entry_t *prev = NULL;
+ drm_magic_entry_t *pt;
+ int hash;
+
+ DRM_DEBUG("%d\n", magic);
+ hash = drm_hash_magic(magic);
+
+ lockmgr(&dev->dev_lock, LK_EXCLUSIVE, 0, curproc);
+ for (pt = dev->magiclist[hash].head; pt; prev = pt, pt = pt->next) {
+ if (pt->magic == magic) {
+ if (dev->magiclist[hash].head == pt) {
+ dev->magiclist[hash].head = pt->next;
+ }
+ if (dev->magiclist[hash].tail == pt) {
+ dev->magiclist[hash].tail = prev;
+ }
+ if (prev) {
+ prev->next = pt->next;
+ }
+ lockmgr(&dev->dev_lock, LK_RELEASE, 0, curproc);
+ return 0;
+ }
+ }
+ lockmgr(&dev->dev_lock, LK_RELEASE, 0, curproc);
+
+ drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
+
+ return EINVAL;
+}
+
+int drm_getmagic(dev_t kdev, u_long cmd, caddr_t data,
+ int flags, struct proc *p)
+{
+ static drm_magic_t sequence = 0;
+#if 0
+ static struct simplelock lock; /* XXX */
+#endif
+ drm_device_t *dev = kdev->si_drv1;
+ drm_file_t *priv;
+ drm_auth_t auth;
+
+ /* Find unique magic */
+ priv = drm_find_file_by_proc(dev, p);
+ if (!priv) {
+ DRM_DEBUG("can't find file structure\n");
+ return EINVAL;
+ }
+ if (priv->magic) {
+ auth.magic = priv->magic;
+ } else {
+ simple_lock(&lock);
+ do {
+ if (!sequence) ++sequence; /* reserve 0 */
+ auth.magic = sequence++;
+ } while (drm_find_file(dev, auth.magic));
+ simple_unlock(&lock);
+ priv->magic = auth.magic;
+ drm_add_magic(dev, priv, auth.magic);
+ }
+
+ DRM_DEBUG("%u\n", auth.magic);
+ *(drm_auth_t *) data = auth;
+ return 0;
+}
+
+int drm_authmagic(dev_t kdev, u_long cmd, caddr_t data,
+ int flags, struct proc *p)
+{
+ drm_device_t *dev = kdev->si_drv1;
+ drm_auth_t auth;
+ drm_file_t *file;
+
+ auth = *(drm_auth_t *) data;
+ DRM_DEBUG("%u\n", auth.magic);
+ if ((file = drm_find_file(dev, auth.magic))) {
+ file->authenticated = 1;
+ drm_remove_magic(dev, auth.magic);
+ return 0;
+ }
+ return EINVAL;
+}
diff --git a/bsd/drm/bufs.c b/bsd/drm/bufs.c
new file mode 100644
index 00000000..fc08b69d
--- /dev/null
+++ b/bsd/drm/bufs.c
@@ -0,0 +1,500 @@
+/* bufs.c -- IOCTLs to manage buffers -*- c -*-
+ * Created: Tue Feb 2 08:37:54 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 22:48:10 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/bufs.c,v 1.8 1999/08/30 13:05:00 faith Exp $
+ * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/bufs.c,v 1.1 1999/09/25 14:37:57 dawes Exp $
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+#include <sys/mman.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_map.h>
+
+ /* Compute order. Can be made faster. */
+int drm_order(unsigned long size)
+{
+ int order;
+ unsigned long tmp;
+
+ for (order = 0, tmp = size; tmp >>= 1; ++order);
+ if (size & ~(1 << order)) ++order;
+ return order;
+}
+
+int drm_addmap(dev_t kdev, u_long cmd, caddr_t data,
+ int flags, struct proc *p)
+{
+ drm_device_t *dev = kdev->si_drv1;
+ drm_map_t *map;
+
+ if (!(dev->flags & (FREAD|FWRITE)))
+ return EACCES; /* Require read/write */
+
+ map = drm_alloc(sizeof(*map), DRM_MEM_MAPS);
+ if (!map) return ENOMEM;
+ *map = *(drm_map_t *) data;
+
+ DRM_DEBUG("offset = 0x%08lx, size = 0x%08lx, type = %d\n",
+ map->offset, map->size, map->type);
+ if ((map->offset & (PAGE_SIZE-1)) || (map->size & (PAGE_SIZE-1))) {
+ drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+ DRM_DEBUG("offset or size not page aligned\n");
+ return EINVAL;
+ }
+ map->mtrr = -1;
+ map->handle = 0;
+
+ switch (map->type) {
+ case _DRM_REGISTERS:
+ case _DRM_FRAME_BUFFER:
+ if (map->offset + map->size < map->offset
+ /* || map->offset < virt_to_phys(high_memory) */) {
+ drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+ DRM_DEBUG("bad frame buffer size\n");
+ return EINVAL;
+ }
+#ifdef CONFIG_MTRR
+ if (map->type == _DRM_FRAME_BUFFER
+ || (map->flags & _DRM_WRITE_COMBINING)) {
+ map->mtrr = mtrr_add(map->offset, map->size,
+ MTRR_TYPE_WRCOMB, 1);
+ }
+#endif
+ map->handle = drm_ioremap(map->offset, map->size);
+ break;
+
+
+ case _DRM_SHM:
+ DRM_DEBUG("%ld %d\n", map->size, drm_order(map->size));
+ map->handle = (void *)drm_alloc_pages(drm_order(map->size)
+ - PAGE_SHIFT,
+ DRM_MEM_SAREA);
+ if (!map->handle) {
+ drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+ return ENOMEM;
+ }
+ map->offset = (unsigned long)map->handle;
+ if (map->flags & _DRM_CONTAINS_LOCK) {
+ dev->lock.hw_lock = map->handle; /* Pointer to lock */
+ }
+ break;
+#ifdef DRM_AGP
+ case _DRM_AGP:
+ map->offset = map->offset + dev->agp->base;
+ break;
+#endif
+ default:
+ drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+ DRM_DEBUG("bad type\n");
+ return EINVAL;
+ }
+
+ lockmgr(&dev->dev_lock, LK_EXCLUSIVE, 0, curproc);
+ if (dev->maplist) {
+ ++dev->map_count;
+ dev->maplist = drm_realloc(dev->maplist,
+ (dev->map_count-1)
+ * sizeof(*dev->maplist),
+ dev->map_count
+ * sizeof(*dev->maplist),
+ DRM_MEM_MAPS);
+ } else {
+ dev->map_count = 1;
+ dev->maplist = drm_alloc(dev->map_count*sizeof(*dev->maplist),
+ DRM_MEM_MAPS);
+ }
+ dev->maplist[dev->map_count-1] = map;
+ lockmgr(&dev->dev_lock, LK_RELEASE, 0, curproc);
+
+ *(drm_map_t *) data = *map;
+ if (map->type != _DRM_SHM)
+ ((drm_map_t *)data)->handle = (void *) map->offset;
+
+ return 0;
+}
+
+int drm_addbufs(dev_t kdev, u_long cmd, caddr_t data,
+ int flags, struct proc *p)
+{
+ drm_device_t *dev = kdev->si_drv1;
+ drm_device_dma_t *dma = dev->dma;
+ drm_buf_desc_t request;
+ int count;
+ int order;
+ int size;
+ int total;
+ int page_order;
+ drm_buf_entry_t *entry;
+ unsigned long page;
+ drm_buf_t *buf;
+ int alignment;
+ unsigned long offset;
+ int i;
+ int byte_count;
+ int page_count;
+
+ if (!dma) return EINVAL;
+
+ request = *(drm_buf_desc_t *) data;
+
+ count = request.count;
+ order = drm_order(request.size);
+ size = 1 << order;
+
+ DRM_DEBUG("count = %d, size = %d (%d), order = %d, queue_count = %d\n",
+ request.count, request.size, size, order, dev->queue_count);
+
+ if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return EINVAL;
+ if (dev->queue_count) return EBUSY; /* Not while in use */
+
+ alignment = (request.flags & _DRM_PAGE_ALIGN) ? round_page(size) :size;
+ page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
+ total = PAGE_SIZE << page_order;
+
+ simple_lock(&dev->count_lock);
+ if (dev->buf_use) {
+ simple_unlock(&dev->count_lock);
+ return EBUSY;
+ }
+ atomic_inc(&dev->buf_alloc);
+ simple_unlock(&dev->count_lock);
+
+ lockmgr(&dev->dev_lock, LK_EXCLUSIVE, 0, curproc);
+ entry = &dma->bufs[order];
+ if (entry->buf_count) {
+ lockmgr(&dev->dev_lock, LK_RELEASE, 0, curproc);
+ atomic_dec(&dev->buf_alloc);
+ return ENOMEM; /* May only call once for each order */
+ }
+
+ entry->buflist = drm_alloc(count * sizeof(*entry->buflist),
+ DRM_MEM_BUFS);
+ if (!entry->buflist) {
+ lockmgr(&dev->dev_lock, LK_RELEASE, 0, curproc);
+ atomic_dec(&dev->buf_alloc);
+ return ENOMEM;
+ }
+ memset(entry->buflist, 0, count * sizeof(*entry->buflist));
+
+ entry->seglist = drm_alloc(count * sizeof(*entry->seglist),
+ DRM_MEM_SEGS);
+ if (!entry->seglist) {
+ drm_free(entry->buflist,
+ count * sizeof(*entry->buflist),
+ DRM_MEM_BUFS);
+ lockmgr(&dev->dev_lock, LK_RELEASE, 0, curproc);
+ atomic_dec(&dev->buf_alloc);
+ return ENOMEM;
+ }
+ memset(entry->seglist, 0, count * sizeof(*entry->seglist));
+
+ dma->pagelist = drm_realloc(dma->pagelist,
+ dma->page_count * sizeof(*dma->pagelist),
+ (dma->page_count + (count << page_order))
+ * sizeof(*dma->pagelist),
+ DRM_MEM_PAGES);
+ DRM_DEBUG("pagelist: %d entries\n",
+ dma->page_count + (count << page_order));
+
+
+ entry->buf_size = size;
+ entry->page_order = page_order;
+ byte_count = 0;
+ page_count = 0;
+ while (entry->buf_count < count) {
+ if (!(page = drm_alloc_pages(page_order, DRM_MEM_DMA))) break;
+ entry->seglist[entry->seg_count++] = page;
+ for (i = 0; i < (1 << page_order); i++) {
+ DRM_DEBUG("page %d @ 0x%08lx\n",
+ dma->page_count + page_count,
+ page + PAGE_SIZE * i);
+ dma->pagelist[dma->page_count + page_count++]
+ = page + PAGE_SIZE * i;
+ }
+ for (offset = 0;
+ offset + size <= total && entry->buf_count < count;
+ offset += alignment, ++entry->buf_count) {
+ buf = &entry->buflist[entry->buf_count];
+ buf->idx = dma->buf_count + entry->buf_count;
+ buf->total = alignment;
+ buf->order = order;
+ buf->used = 0;
+ buf->offset = (dma->byte_count + byte_count + offset);
+ buf->address = (void *)(page + offset);
+ buf->next = NULL;
+ buf->waiting = 0;
+ buf->pending = 0;
+ buf->dma_wait = 0;
+ buf->pid = 0;
+#if DRM_DMA_HISTOGRAM
+ timespecclear(&buf->time_queued);
+ timespecclear(&buf->time_dispatched);
+ timespecclear(&buf->time_completed);
+ timespecclear(&buf->time_freed);
+#endif
+ DRM_DEBUG("buffer %d @ %p\n",
+ entry->buf_count, buf->address);
+ }
+ byte_count += PAGE_SIZE << page_order;
+ }
+
+ dma->buflist = drm_realloc(dma->buflist,
+ dma->buf_count * sizeof(*dma->buflist),
+ (dma->buf_count + entry->buf_count)
+ * sizeof(*dma->buflist),
+ DRM_MEM_BUFS);
+ for (i = dma->buf_count; i < dma->buf_count + entry->buf_count; i++)
+ dma->buflist[i] = &entry->buflist[i - dma->buf_count];
+
+ dma->buf_count += entry->buf_count;
+ dma->seg_count += entry->seg_count;
+ dma->page_count += entry->seg_count << page_order;
+ dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order);
+
+ drm_freelist_create(&entry->freelist, entry->buf_count);
+ for (i = 0; i < entry->buf_count; i++) {
+ drm_freelist_put(dev, &entry->freelist, &entry->buflist[i]);
+ }
+
+ lockmgr(&dev->dev_lock, LK_RELEASE, 0, curproc);
+
+ request.count = entry->buf_count;
+ request.size = size;
+
+ *(drm_buf_desc_t *) data = request;
+
+ atomic_dec(&dev->buf_alloc);
+ return 0;
+}
+
+int drm_infobufs(dev_t kdev, u_long cmd, caddr_t data,
+ int flags, struct proc *p)
+{
+ drm_device_t *dev = kdev->si_drv1;
+ drm_device_dma_t *dma = dev->dma;
+ drm_buf_info_t request;
+ int i;
+ int count;
+
+ if (!dma) return EINVAL;
+
+ simple_lock(&dev->count_lock);
+ if (atomic_read(&dev->buf_alloc)) {
+ simple_unlock(&dev->count_lock);
+ return EBUSY;
+ }
+ ++dev->buf_use; /* Can't allocate more after this call */
+ simple_unlock(&dev->count_lock);
+
+ request = *(drm_buf_info_t *) data;
+
+ for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) {
+ if (dma->bufs[i].buf_count) ++count;
+ }
+
+ DRM_DEBUG("count = %d\n", count);
+
+ if (request.count >= count) {
+ for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) {
+ if (dma->bufs[i].buf_count) {
+ int error;
+ error = copyout(&dma->bufs[i].buf_count,
+ &request.list[count].count,
+ sizeof(dma->bufs[0]
+ .buf_count));
+ if (error) return error;
+ error = copyout(&dma->bufs[i].buf_size,
+ &request.list[count].size,
+ sizeof(dma->bufs[0].buf_size));
+ if (error) return error;
+ error = copyout(&dma->bufs[i]
+ .freelist.low_mark,
+ &request.list[count].low_mark,
+ sizeof(dma->bufs[0]
+ .freelist.low_mark));
+ if (error) return error;
+ error = copyout(&dma->bufs[i]
+ .freelist.high_mark,
+ &request.list[count].high_mark,
+ sizeof(dma->bufs[0]
+ .freelist.high_mark));
+ if (error) return error;
+ DRM_DEBUG("%d %d %d %d %d\n",
+ i,
+ dma->bufs[i].buf_count,
+ dma->bufs[i].buf_size,
+ dma->bufs[i].freelist.low_mark,
+ dma->bufs[i].freelist.high_mark);
+ ++count;
+ }
+ }
+ }
+ request.count = count;
+
+ *(drm_buf_info_t *) data = request;
+
+ return 0;
+}
+
+int drm_markbufs(dev_t kdev, u_long cmd, caddr_t data,
+ int flags, struct proc *p)
+{
+ drm_device_t *dev = kdev->si_drv1;
+ drm_device_dma_t *dma = dev->dma;
+ drm_buf_desc_t request;
+ int order;
+ drm_buf_entry_t *entry;
+
+ if (!dma) return EINVAL;
+
+ request = *(drm_buf_desc_t *) data;
+
+ DRM_DEBUG("%d, %d, %d\n",
+ request.size, request.low_mark, request.high_mark);
+ order = drm_order(request.size);
+ if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return EINVAL;
+ entry = &dma->bufs[order];
+
+ if (request.low_mark < 0 || request.low_mark > entry->buf_count)
+ return EINVAL;
+ if (request.high_mark < 0 || request.high_mark > entry->buf_count)
+ return EINVAL;
+
+ entry->freelist.low_mark = request.low_mark;
+ entry->freelist.high_mark = request.high_mark;
+
+ return 0;
+}
+
+int drm_freebufs(dev_t kdev, u_long cmd, caddr_t data,
+ int flags, struct proc *p)
+{
+ drm_device_t *dev = kdev->si_drv1;
+ drm_device_dma_t *dma = dev->dma;
+ drm_buf_free_t request;
+ int i;
+ int idx;
+ int error;
+ drm_buf_t *buf;
+
+ if (!dma) return EINVAL;
+
+ request = *(drm_buf_free_t *) data;
+
+ DRM_DEBUG("%d\n", request.count);
+ for (i = 0; i < request.count; i++) {
+ error = copyin(&request.list[i], &idx, sizeof(idx));
+ if (error)
+ return error;
+ if (idx < 0 || idx >= dma->buf_count) {
+ DRM_ERROR("Index %d (of %d max)\n",
+ idx, dma->buf_count - 1);
+ return EINVAL;
+ }
+ buf = dma->buflist[idx];
+ if (buf->pid != p->p_pid) {
+ DRM_ERROR("Process %d freeing buffer owned by %d\n",
+ p->p_pid, buf->pid);
+ return EINVAL;
+ }
+ drm_free_buffer(dev, buf);
+ }
+
+ return 0;
+}
+
+int drm_mapbufs(dev_t kdev, u_long cmd, caddr_t data,
+ int flags, struct proc *p)
+{
+ drm_device_t *dev = kdev->si_drv1;
+ drm_device_dma_t *dma = dev->dma;
+ int retcode = 0;
+ const int zero = 0;
+ vm_offset_t virtual;
+ vm_offset_t address;
+ drm_buf_map_t request;
+ int i;
+
+ if (!dma) return EINVAL;
+
+ DRM_DEBUG("\n");
+
+ simple_lock(&dev->count_lock);
+ if (atomic_read(&dev->buf_alloc)) {
+ simple_unlock(&dev->count_lock);
+ return EBUSY;
+ }
+ ++dev->buf_use; /* Can't allocate more after this call */
+ simple_unlock(&dev->count_lock);
+
+ request = *(drm_buf_map_t *) data;
+
+ if (request.count >= dma->buf_count) {
+ virtual = 0;
+ retcode = vm_mmap(&p->p_vmspace->vm_map,
+ &virtual,
+ round_page(dma->byte_count),
+ PROT_READ|PROT_WRITE, VM_PROT_ALL,
+ MAP_SHARED,
+ SLIST_FIRST(&kdev->si_hlist),
+ 0);
+ if (retcode)
+ goto done;
+
+ request.virtual = (void *)virtual;
+
+ for (i = 0; i < dma->buf_count; i++) {
+ retcode = copyout(&dma->buflist[i]->idx,
+ &request.list[i].idx,
+ sizeof(request.list[0].idx));
+ if (retcode) goto done;
+ retcode = copyout(&dma->buflist[i]->total,
+ &request.list[i].total,
+ sizeof(request.list[0].total));
+ if (retcode) goto done;
+ retcode = copyout(&zero,
+ &request.list[i].used,
+ sizeof(request.list[0].used));
+ if (retcode) goto done;
+ address = virtual + dma->buflist[i]->offset;
+ retcode = copyout(&address,
+ &request.list[i].address,
+ sizeof(address));
+ if (retcode) goto done;
+ }
+ }
+done:
+ request.count = dma->buf_count;
+ DRM_DEBUG("%d buffers, retcode = %d\n", request.count, retcode);
+
+ *(drm_buf_map_t *) data = request;
+
+ return retcode;
+}
diff --git a/bsd/drm/context.c b/bsd/drm/context.c
new file mode 100644
index 00000000..d79990f8
--- /dev/null
+++ b/bsd/drm/context.c
@@ -0,0 +1,297 @@
+/* context.c -- IOCTLs for contexts and DMA queues -*- c -*-
+ * Created: Tue Feb 2 08:37:54 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 11:32:09 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/context.c,v 1.5 1999/08/30 13:05:00 faith Exp $
+ * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/context.c,v 1.1 1999/09/25 14:37:58 dawes Exp $
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+static int drm_init_queue(drm_device_t *dev, drm_queue_t *q, drm_ctx_t *ctx)
+{
+ DRM_DEBUG("\n");
+
+ if (atomic_read(&q->use_count) != 1
+ || atomic_read(&q->finalization)
+ || atomic_read(&q->block_count)) {
+ DRM_ERROR("New queue is already in use: u%d f%d b%d\n",
+ atomic_read(&q->use_count),
+ atomic_read(&q->finalization),
+ atomic_read(&q->block_count));
+ }
+
+ atomic_set(&q->finalization, 0);
+ atomic_set(&q->block_count, 0);
+ atomic_set(&q->block_read, 0);
+ atomic_set(&q->block_write, 0);
+ atomic_set(&q->total_queued, 0);
+ atomic_set(&q->total_flushed, 0);
+ atomic_set(&q->total_locks, 0);
+
+ q->write_queue = 0;
+ q->read_queue = 0;
+ q->flush_queue = 0;
+
+ q->flags = ctx->flags;
+
+ drm_waitlist_create(&q->waitlist, dev->dma->buf_count);
+
+ return 0;
+}
+
+
+/* drm_alloc_queue:
+PRE: 1) dev->queuelist[0..dev->queue_count] is allocated and will not
+ disappear (so all deallocation must be done after IOCTLs are off)
+ 2) dev->queue_count < dev->queue_slots
+ 3) dev->queuelist[i].use_count == 0 and
+ dev->queuelist[i].finalization == 0 if i not in use
+POST: 1) dev->queuelist[i].use_count == 1
+ 2) dev->queue_count < dev->queue_slots */
+
+static int drm_alloc_queue(drm_device_t *dev)
+{
+ int i;
+ drm_queue_t *queue;
+ int oldslots;
+ int newslots;
+ /* Check for a free queue */
+ for (i = 0; i < dev->queue_count; i++) {
+ atomic_inc(&dev->queuelist[i]->use_count);
+ if (atomic_read(&dev->queuelist[i]->use_count) == 1
+ && !atomic_read(&dev->queuelist[i]->finalization)) {
+ DRM_DEBUG("%d (free)\n", i);
+ return i;
+ }
+ atomic_dec(&dev->queuelist[i]->use_count);
+ }
+ /* Allocate a new queue */
+ lockmgr(&dev->dev_lock, LK_EXCLUSIVE, 0, curproc);
+
+ queue = drm_alloc(sizeof(*queue), DRM_MEM_QUEUES);
+ memset(queue, 0, sizeof(*queue));
+ atomic_set(&queue->use_count, 1);
+
+ ++dev->queue_count;
+ if (dev->queue_count >= dev->queue_slots) {
+ oldslots = dev->queue_slots * sizeof(*dev->queuelist);
+ if (!dev->queue_slots) dev->queue_slots = 1;
+ dev->queue_slots *= 2;
+ newslots = dev->queue_slots * sizeof(*dev->queuelist);
+
+ dev->queuelist = drm_realloc(dev->queuelist,
+ oldslots,
+ newslots,
+ DRM_MEM_QUEUES);
+ if (!dev->queuelist) {
+ lockmgr(&dev->dev_lock, LK_RELEASE, 0, curproc);
+ DRM_DEBUG("out of memory\n");
+ return -ENOMEM;
+ }
+ }
+ dev->queuelist[dev->queue_count-1] = queue;
+
+ lockmgr(&dev->dev_lock, LK_RELEASE, 0, curproc);
+ DRM_DEBUG("%d (new)\n", dev->queue_count - 1);
+ return dev->queue_count - 1;
+}
+
+int drm_resctx(dev_t kdev, u_long cmd, caddr_t data, int flags, struct proc *p)
+{
+ drm_ctx_res_t res;
+ drm_ctx_t ctx;
+ int i;
+ int error;
+
+ DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS);
+ res = *(drm_ctx_res_t *) data;
+ if (res.count >= DRM_RESERVED_CONTEXTS) {
+ memset(&ctx, 0, sizeof(ctx));
+ for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
+ ctx.handle = i;
+ error = copyout(&i, &res.contexts[i],
+ sizeof(i));
+ if (error) return error;
+ }
+ }
+ res.count = DRM_RESERVED_CONTEXTS;
+ *(drm_ctx_res_t *) data = res;
+ return 0;
+}
+
+
+int drm_addctx(dev_t kdev, u_long cmd, caddr_t data, int flags, struct proc *p)
+{
+ drm_device_t *dev = kdev->si_drv1;
+ drm_ctx_t ctx;
+
+ ctx = *(drm_ctx_t *) data;
+ if ((ctx.handle = drm_alloc_queue(dev)) == DRM_KERNEL_CONTEXT) {
+ /* Init kernel's context and get a new one. */
+ drm_init_queue(dev, dev->queuelist[ctx.handle], &ctx);
+ ctx.handle = drm_alloc_queue(dev);
+ }
+ drm_init_queue(dev, dev->queuelist[ctx.handle], &ctx);
+ DRM_DEBUG("%d\n", ctx.handle);
+ *(drm_ctx_t *) data = ctx;
+ return 0;
+}
+
+int drm_modctx(dev_t kdev, u_long cmd, caddr_t data, int flags, struct proc *p)
+{
+ drm_device_t *dev = kdev->si_drv1;
+ drm_ctx_t ctx;
+ drm_queue_t *q;
+
+ ctx = *(drm_ctx_t *) data;
+
+ DRM_DEBUG("%d\n", ctx.handle);
+
+ if (ctx.handle < 0 || ctx.handle >= dev->queue_count) return -EINVAL;
+ q = dev->queuelist[ctx.handle];
+
+ atomic_inc(&q->use_count);
+ if (atomic_read(&q->use_count) == 1) {
+ /* No longer in use */
+ atomic_dec(&q->use_count);
+ return -EINVAL;
+ }
+
+ if (DRM_BUFCOUNT(&q->waitlist)) {
+ atomic_dec(&q->use_count);
+ return -EBUSY;
+ }
+
+ q->flags = ctx.flags;
+
+ atomic_dec(&q->use_count);
+ return 0;
+}
+
+int drm_getctx(dev_t kdev, u_long cmd, caddr_t data, int flags, struct proc *p)
+{
+ drm_device_t *dev = kdev->si_drv1;
+ drm_ctx_t ctx;
+ drm_queue_t *q;
+
+ ctx = *(drm_ctx_t *) data;
+
+ DRM_DEBUG("%d\n", ctx.handle);
+
+ if (ctx.handle >= dev->queue_count) return -EINVAL;
+ q = dev->queuelist[ctx.handle];
+
+ atomic_inc(&q->use_count);
+ if (atomic_read(&q->use_count) == 1) {
+ /* No longer in use */
+ atomic_dec(&q->use_count);
+ return -EINVAL;
+ }
+
+ ctx.flags = q->flags;
+ atomic_dec(&q->use_count);
+
+ *(drm_ctx_t *) data = ctx;
+
+ return 0;
+}
+
+int drm_switchctx(dev_t kdev, u_long cmd, caddr_t data, int flags, struct proc *p)
+{
+ drm_device_t *dev = kdev->si_drv1;
+ drm_ctx_t ctx;
+
+ ctx = *(drm_ctx_t *) data;
+ DRM_DEBUG("%d\n", ctx.handle);
+ return drm_context_switch(dev, dev->last_context, ctx.handle);
+}
+
+int drm_newctx(dev_t kdev, u_long cmd, caddr_t data, int flags, struct proc *p)
+{
+ drm_device_t *dev = kdev->si_drv1;
+ drm_ctx_t ctx;
+
+ ctx = *(drm_ctx_t *) data;
+ DRM_DEBUG("%d\n", ctx.handle);
+ drm_context_switch_complete(dev, ctx.handle);
+
+ return 0;
+}
+
+int drm_rmctx(dev_t kdev, u_long cmd, caddr_t data, int flags, struct proc *p)
+{
+ drm_device_t *dev = kdev->si_drv1;
+ drm_ctx_t ctx;
+ drm_queue_t *q;
+ drm_buf_t *buf;
+
+ ctx = *(drm_ctx_t *) data;
+ DRM_DEBUG("%d\n", ctx.handle);
+
+ if (ctx.handle >= dev->queue_count) return -EINVAL;
+ q = dev->queuelist[ctx.handle];
+
+ atomic_inc(&q->use_count);
+ if (atomic_read(&q->use_count) == 1) {
+ /* No longer in use */
+ atomic_dec(&q->use_count);
+ return -EINVAL;
+ }
+
+ atomic_inc(&q->finalization); /* Mark queue in finalization state */
+ atomic_sub(2, &q->use_count); /* Mark queue as unused (pending
+ finalization) */
+
+ /* Wait while interrupt servicing is in progress */
+ while (test_and_set_bit(0, &dev->interrupt_flag)) {
+ int never;
+ int error = tsleep(&never, PZERO|PCATCH, "drmrc", 1);
+ if (error) {
+ clear_bit(0, &dev->interrupt_flag);
+ return error;
+ }
+ }
+ /* Remove queued buffers */
+ while ((buf = drm_waitlist_get(&q->waitlist))) {
+ drm_free_buffer(dev, buf);
+ }
+ clear_bit(0, &dev->interrupt_flag);
+
+ /* Wakeup blocked processes */
+ wakeup(&q->read_queue);
+ wakeup(&q->write_queue);
+ wakeup(&q->flush_queue);
+
+ /* Finalization over. Queue is made
+ available when both use_count and
+ finalization become 0, which won't
+ happen until all the waiting processes
+ stop waiting. */
+ atomic_dec(&q->finalization);
+ return 0;
+}
diff --git a/bsd/drm/dma.c b/bsd/drm/dma.c
new file mode 100644
index 00000000..149f4593
--- /dev/null
+++ b/bsd/drm/dma.c
@@ -0,0 +1,534 @@
+/* dma.c -- DMA IOCTL and function support -*- c -*-
+ * Created: Fri Mar 19 14:30:16 1999 by faith@precisioninsight.com
+ * Revised: Thu Sep 16 12:55:39 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/dma.c,v 1.7 1999/09/16 16:56:18 faith Exp $
+ * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/dma.c,v 1.1 1999/09/25 14:37:58 dawes Exp $
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+void drm_dma_setup(drm_device_t *dev)
+{
+ int i;
+
+ dev->dma = drm_alloc(sizeof(*dev->dma), DRM_MEM_DRIVER);
+ memset(dev->dma, 0, sizeof(*dev->dma));
+ for (i = 0; i <= DRM_MAX_ORDER; i++)
+ memset(&dev->dma->bufs[i], 0, sizeof(dev->dma->bufs[0]));
+}
+
+void drm_dma_takedown(drm_device_t *dev)
+{
+ drm_device_dma_t *dma = dev->dma;
+ int i, j;
+
+ if (!dma) return;
+
+ /* Clear dma buffers */
+ for (i = 0; i <= DRM_MAX_ORDER; i++) {
+ if (dma->bufs[i].seg_count) {
+ DRM_DEBUG("order %d: buf_count = %d,"
+ " seg_count = %d\n",
+ i,
+ dma->bufs[i].buf_count,
+ dma->bufs[i].seg_count);
+ for (j = 0; j < dma->bufs[i].seg_count; j++) {
+ drm_free_pages(dma->bufs[i].seglist[j],
+ 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->buflist) {
+ drm_free(dma->buflist,
+ dma->buf_count * sizeof(*dma->buflist),
+ DRM_MEM_BUFS);
+ }
+
+ if (dma->pagelist) {
+ drm_free(dma->pagelist,
+ dma->page_count * sizeof(*dma->pagelist),
+ DRM_MEM_PAGES);
+ }
+ drm_free(dev->dma, sizeof(*dev->dma), DRM_MEM_DRIVER);
+ dev->dma = NULL;
+}
+
+#if DRM_DMA_HISTOGRAM
+/* This is slow, but is useful for debugging. */
+int drm_histogram_slot(struct timespec *ts)
+{
+ long count = ts->tv_sec * 1000 + ts->tv_nsec / 1000000;
+ int value = DRM_DMA_HISTOGRAM_INITIAL;
+ int slot;
+
+ for (slot = 0;
+ slot < DRM_DMA_HISTOGRAM_SLOTS;
+ ++slot, value = DRM_DMA_HISTOGRAM_NEXT(value)) {
+ if (count < value) return slot;
+ }
+ return DRM_DMA_HISTOGRAM_SLOTS - 1;
+}
+
+void drm_histogram_compute(drm_device_t *dev, drm_buf_t *buf)
+{
+ struct timespec queued_to_dispatched;
+ struct timespec dispatched_to_completed;
+ struct timespec completed_to_freed;
+ int q2d, d2c, c2f, q2c, q2f;
+
+ if (timespecisset(&buf->time_queued)) {
+ queued_to_dispatched = buf->time_dispatched;
+ timespecsub(&queued_to_dispatched, &buf->time_queued);
+ dispatched_to_completed = buf->time_completed;
+ timespecsub(&dispatched_to_completed, &buf->time_dispatched);
+ completed_to_freed = buf->time_freed;
+ timespecsub(&completed_to_freed, &buf->time_completed);
+
+ q2d = drm_histogram_slot(&queued_to_dispatched);
+ d2c = drm_histogram_slot(&dispatched_to_completed);
+ c2f = drm_histogram_slot(&completed_to_freed);
+
+ timespecadd(&queued_to_dispatched, &dispatched_to_completed);
+ q2c = drm_histogram_slot(&queued_to_dispatched);
+ timespecadd(&queued_to_dispatched, &completed_to_freed);
+ q2f = drm_histogram_slot(&queued_to_dispatched);
+
+ atomic_inc(&dev->histo.total);
+ atomic_inc(&dev->histo.queued_to_dispatched[q2d]);
+ atomic_inc(&dev->histo.dispatched_to_completed[d2c]);
+ atomic_inc(&dev->histo.completed_to_freed[c2f]);
+
+ atomic_inc(&dev->histo.queued_to_completed[q2c]);
+ atomic_inc(&dev->histo.queued_to_freed[q2f]);
+
+ }
+ timespecclear(&buf->time_queued);
+ timespecclear(&buf->time_dispatched);
+ timespecclear(&buf->time_completed);
+ timespecclear(&buf->time_freed);
+}
+#endif
+
+void drm_free_buffer(drm_device_t *dev, drm_buf_t *buf)
+{
+ drm_device_dma_t *dma = dev->dma;
+
+ if (!buf) return;
+
+ buf->waiting = 0;
+ buf->pending = 0;
+ buf->pid = 0;
+ buf->used = 0;
+#if DRM_DMA_HISTOGRAMxx
+ buf->time_completed = get_cycles();
+#endif
+ if (buf->dma_wait) {
+ buf->dma_wait = 0;
+ wakeup(&buf->dma_wait);
+ } else {
+ /* If processes are waiting, the last one
+ to wake will put the buffer on the free
+ list. If no processes are waiting, we
+ put the buffer on the freelist here. */
+ drm_freelist_put(dev, &dma->bufs[buf->order].freelist, buf);
+ }
+}
+
+void drm_reclaim_buffers(drm_device_t *dev, pid_t pid)
+{
+ drm_device_dma_t *dma = dev->dma;
+ int i;
+
+ if (!dma) return;
+ for (i = 0; i < dma->buf_count; i++) {
+ if (dma->buflist[i]->pid == pid) {
+ switch (dma->buflist[i]->list) {
+ case DRM_LIST_NONE:
+ drm_free_buffer(dev, dma->buflist[i]);
+ break;
+ case DRM_LIST_WAIT:
+ dma->buflist[i]->list = DRM_LIST_RECLAIM;
+ break;
+ default:
+ /* Buffer already on hardware. */
+ break;
+ }
+ }
+ }
+}
+
+int drm_context_switch(drm_device_t *dev, int old, int new)
+{
+ char buf[64];
+ drm_queue_t *q;
+
+ atomic_inc(&dev->total_ctx);
+
+ if (test_and_set_bit(0, &dev->context_flag)) {
+ DRM_ERROR("Reentering -- FIXME\n");
+ return EBUSY;
+ }
+
+#if DRM_DMA_HISTOGRAM
+ getnanotime(&dev->ctx_start);
+#endif
+
+ DRM_DEBUG("Context switch from %d to %d\n", old, new);
+
+ if (new >= dev->queue_count) {
+ clear_bit(0, &dev->context_flag);
+ return EINVAL;
+ }
+
+ if (new == dev->last_context) {
+ clear_bit(0, &dev->context_flag);
+ return 0;
+ }
+
+ q = dev->queuelist[new];
+ atomic_inc(&q->use_count);
+ if (atomic_read(&q->use_count) == 1) {
+ atomic_dec(&q->use_count);
+ clear_bit(0, &dev->context_flag);
+ return EINVAL;
+ }
+
+ if (drm_flags & DRM_FLAG_NOCTX) {
+ drm_context_switch_complete(dev, new);
+ } else {
+ sprintf(buf, "C %d %d\n", old, new);
+ drm_write_string(dev, buf);
+ }
+
+ atomic_dec(&q->use_count);
+
+ return 0;
+}
+
+int drm_context_switch_complete(drm_device_t *dev, int new)
+{
+ drm_device_dma_t *dma = dev->dma;
+
+ dev->last_context = new; /* PRE/POST: This is the _only_ writer. */
+ dev->last_switch = ticks;
+
+ if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+ DRM_ERROR("Lock isn't held after context switch\n");
+ }
+
+ if (!dma || !(dma->next_buffer && dma->next_buffer->while_locked)) {
+ if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
+ DRM_KERNEL_CONTEXT)) {
+ DRM_ERROR("Cannot free lock\n");
+ }
+ }
+
+#if DRM_DMA_HISTOGRAM
+ {
+ struct timespec ts;
+ getnanotime(&ts);
+ timespecsub(&ts, &dev->ctx_start);
+ atomic_inc(&dev->histo.ctx[drm_histogram_slot(&ts)]);
+ }
+#endif
+ clear_bit(0, &dev->context_flag);
+ wakeup(&dev->context_wait);
+
+ return 0;
+}
+
+void drm_clear_next_buffer(drm_device_t *dev)
+{
+ drm_device_dma_t *dma = dev->dma;
+
+ dma->next_buffer = NULL;
+ if (dma->next_queue && !DRM_BUFCOUNT(&dma->next_queue->waitlist)) {
+ wakeup(&dma->next_queue->flush_queue);
+ }
+ dma->next_queue = NULL;
+}
+
+
+int drm_select_queue(drm_device_t *dev, void (*wrapper)(void *))
+{
+ int i;
+ int candidate = -1;
+ int j = ticks;
+
+ if (!dev) {
+ DRM_ERROR("No device\n");
+ return -1;
+ }
+ if (!dev->queuelist || !dev->queuelist[DRM_KERNEL_CONTEXT]) {
+ /* This only happens between the time the
+ interrupt is initialized and the time
+ the queues are initialized. */
+ return -1;
+ }
+
+ /* Doing "while locked" DMA? */
+ if (DRM_WAITCOUNT(dev, DRM_KERNEL_CONTEXT)) {
+ return DRM_KERNEL_CONTEXT;
+ }
+
+ /* If there are buffers on the last_context
+ queue, and we have not been executing
+ this context very long, continue to
+ execute this context. */
+ if (dev->last_switch <= j
+ && dev->last_switch + DRM_TIME_SLICE > j
+ && DRM_WAITCOUNT(dev, dev->last_context)) {
+ return dev->last_context;
+ }
+
+ /* Otherwise, find a candidate */
+ for (i = dev->last_checked + 1; i < dev->queue_count; i++) {
+ if (DRM_WAITCOUNT(dev, i)) {
+ candidate = dev->last_checked = i;
+ break;
+ }
+ }
+
+ if (candidate < 0) {
+ for (i = 0; i < dev->queue_count; i++) {
+ if (DRM_WAITCOUNT(dev, i)) {
+ candidate = dev->last_checked = i;
+ break;
+ }
+ }
+ }
+
+ if (wrapper
+ && candidate >= 0
+ && candidate != dev->last_context
+ && dev->last_switch <= j
+ && dev->last_switch + DRM_TIME_SLICE > j) {
+ int s = splclock();
+ if (dev->timer.c_time != dev->last_switch + DRM_TIME_SLICE) {
+ callout_reset(&dev->timer,
+ dev->last_switch + DRM_TIME_SLICE - j,
+ wrapper,
+ dev);
+ }
+ splx(s);
+ return -1;
+ }
+
+ return candidate;
+}
+
+
+int drm_dma_enqueue(drm_device_t *dev, drm_dma_t *d)
+{
+ int i;
+ drm_queue_t *q;
+ drm_buf_t *buf;
+ int idx;
+ int while_locked = 0;
+ drm_device_dma_t *dma = dev->dma;
+ int error;
+
+ DRM_DEBUG("%d\n", d->send_count);
+
+ if (d->flags & _DRM_DMA_WHILE_LOCKED) {
+ int context = dev->lock.hw_lock->lock;
+
+ if (!_DRM_LOCK_IS_HELD(context)) {
+ DRM_ERROR("No lock held during \"while locked\""
+ " request\n");
+ return EINVAL;
+ }
+ if (d->context != _DRM_LOCKING_CONTEXT(context)
+ && _DRM_LOCKING_CONTEXT(context) != DRM_KERNEL_CONTEXT) {
+ DRM_ERROR("Lock held by %d while %d makes"
+ " \"while locked\" request\n",
+ _DRM_LOCKING_CONTEXT(context),
+ d->context);
+ return EINVAL;
+ }
+ q = dev->queuelist[DRM_KERNEL_CONTEXT];
+ while_locked = 1;
+ } else {
+ q = dev->queuelist[d->context];
+ }
+
+
+ atomic_inc(&q->use_count);
+ if (atomic_read(&q->block_write)) {
+ atomic_inc(&q->block_count);
+ for (;;) {
+ if (!atomic_read(&q->block_write)) break;
+ error = tsleep(&q->block_write, PZERO|PCATCH,
+ "dmawr", 0);
+ if (error) {
+ atomic_dec(&q->use_count);
+ return error;
+ }
+ }
+ atomic_dec(&q->block_count);
+ }
+
+ for (i = 0; i < d->send_count; i++) {
+ idx = d->send_indices[i];
+ if (idx < 0 || idx >= dma->buf_count) {
+ atomic_dec(&q->use_count);
+ DRM_ERROR("Index %d (of %d max)\n",
+ d->send_indices[i], dma->buf_count - 1);
+ return EINVAL;
+ }
+ buf = dma->buflist[ idx ];
+ if (buf->pid != curproc->p_pid) {
+ atomic_dec(&q->use_count);
+ DRM_ERROR("Process %d using buffer owned by %d\n",
+ curproc->p_pid, buf->pid);
+ return EINVAL;
+ }
+ if (buf->list != DRM_LIST_NONE) {
+ atomic_dec(&q->use_count);
+ DRM_ERROR("Process %d using buffer %d on list %d\n",
+ curproc->p_pid, buf->idx, buf->list);
+ }
+ buf->used = d->send_sizes[i];
+ buf->while_locked = while_locked;
+ buf->context = d->context;
+ if (!buf->used) {
+ DRM_ERROR("Queueing 0 length buffer\n");
+ }
+ if (buf->pending) {
+ atomic_dec(&q->use_count);
+ DRM_ERROR("Queueing pending buffer:"
+ " buffer %d, offset %d\n",
+ d->send_indices[i], i);
+ return EINVAL;
+ }
+ if (buf->waiting) {
+ atomic_dec(&q->use_count);
+ DRM_ERROR("Queueing waiting buffer:"
+ " buffer %d, offset %d\n",
+ d->send_indices[i], i);
+ return EINVAL;
+ }
+ buf->waiting = 1;
+ if (atomic_read(&q->use_count) == 1
+ || atomic_read(&q->finalization)) {
+ drm_free_buffer(dev, buf);
+ } else {
+ drm_waitlist_put(&q->waitlist, buf);
+ atomic_inc(&q->total_queued);
+ }
+ }
+ atomic_dec(&q->use_count);
+
+ return 0;
+}
+
+static int drm_dma_get_buffers_of_order(drm_device_t *dev, drm_dma_t *d,
+ int order)
+{
+ int i;
+ int error;
+ drm_buf_t *buf;
+ drm_device_dma_t *dma = dev->dma;
+
+ for (i = d->granted_count; i < d->request_count; i++) {
+ buf = drm_freelist_get(&dma->bufs[order].freelist,
+ d->flags & _DRM_DMA_WAIT);
+ if (!buf) break;
+ if (buf->pending || buf->waiting) {
+ DRM_ERROR("Free buffer %d in use by %d (w%d, p%d)\n",
+ buf->idx,
+ buf->pid,
+ buf->waiting,
+ buf->pending);
+ }
+ buf->pid = curproc->p_pid;
+ error = copyout(&buf->idx,
+ &d->request_indices[i],
+ sizeof(buf->idx));
+ if (error)
+ return error;
+ error = copyout(&buf->total,
+ &d->request_sizes[i],
+ sizeof(buf->total));
+ if (error)
+ return error;
+ ++d->granted_count;
+ }
+ return 0;
+}
+
+
+int drm_dma_get_buffers(drm_device_t *dev, drm_dma_t *dma)
+{
+ int order;
+ int retcode = 0;
+ int tmp_order;
+
+ order = drm_order(dma->request_size);
+
+ dma->granted_count = 0;
+ retcode = drm_dma_get_buffers_of_order(dev, dma, order);
+
+ if (dma->granted_count < dma->request_count
+ && (dma->flags & _DRM_DMA_SMALLER_OK)) {
+ for (tmp_order = order - 1;
+ !retcode
+ && dma->granted_count < dma->request_count
+ && tmp_order >= DRM_MIN_ORDER;
+ --tmp_order) {
+
+ retcode = drm_dma_get_buffers_of_order(dev, dma,
+ tmp_order);
+ }
+ }
+
+ if (dma->granted_count < dma->request_count
+ && (dma->flags & _DRM_DMA_LARGER_OK)) {
+ for (tmp_order = order + 1;
+ !retcode
+ && dma->granted_count < dma->request_count
+ && tmp_order <= DRM_MAX_ORDER;
+ ++tmp_order) {
+
+ retcode = drm_dma_get_buffers_of_order(dev, dma,
+ tmp_order);
+ }
+ }
+ return 0;
+}
diff --git a/bsd/drm/drawable.c b/bsd/drm/drawable.c
new file mode 100644
index 00000000..d8005af6
--- /dev/null
+++ b/bsd/drm/drawable.c
@@ -0,0 +1,50 @@
+/* drawable.c -- IOCTLs for drawables -*- c -*-
+ * Created: Tue Feb 2 08:37:54 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 09:27:03 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/drawable.c,v 1.3 1999/08/30 13:05:00 faith Exp $
+ * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/drawable.c,v 1.1 1999/09/25 14:37:58 dawes Exp $
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+int drm_adddraw(dev_t kdev, u_long cmd, caddr_t data,
+ int flags, struct proc *p)
+{
+ drm_draw_t draw;
+
+ draw.handle = 0; /* NOOP */
+ DRM_DEBUG("%d\n", draw.handle);
+ *(drm_draw_t *) data = draw;
+ return 0;
+}
+
+int drm_rmdraw(dev_t kdev, u_long cmd, caddr_t data,
+ int flags, struct proc *p)
+{
+ return 0; /* NOOP */
+}
diff --git a/bsd/drm/drmstat.c b/bsd/drm/drmstat.c
new file mode 100644
index 00000000..0ce76b01
--- /dev/null
+++ b/bsd/drm/drmstat.c
@@ -0,0 +1,418 @@
+/* drmstat.c -- DRM device status and testing program
+ * Created: Tue Jan 5 08:19:24 1999 by faith@precisioninsight.com
+ * Revised: Sun Aug 1 11:02:00 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/drmstat.c,v 1.28 1999/08/04 18:12:11 faith Exp $
+ * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/drmstat.c,v 1.1 1999/09/25 14:37:59 dawes Exp $
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <strings.h>
+#include <errno.h>
+#include <signal.h>
+#include <fcntl.h>
+#include "xf86drm.h"
+
+int sigio_fd;
+
+static double usec(struct timeval *end, struct timeval *start)
+{
+ double e = end->tv_sec * 1000000 + end->tv_usec;
+ double s = start->tv_sec * 1000000 + start->tv_usec;
+
+ return e - s;
+}
+
+static void getversion(int fd)
+{
+ drmVersionPtr version;
+
+ version = drmGetVersion(fd);
+ if (version) {
+ printf( "Name: %s\n", version->name ? version->name : "?" );
+ printf( " Version: %d.%d.%d\n",
+ version->version_major,
+ version->version_minor,
+ version->version_patchlevel );
+ printf( " Date: %s\n", version->date ? version->date : "?" );
+ printf( " Desc: %s\n", version->desc ? version->desc : "?" );
+ drmFreeVersion(version);
+ } else {
+ printf( "No driver available\n" );
+ }
+}
+
+void handler(int fd, void *oldctx, void *newctx)
+{
+ printf("Got fd %d\n", fd);
+}
+
+void process_sigio(char *device)
+{
+ int fd;
+
+printf("%s\n", device);
+ if ((fd = open(device, 0)) < 0) {
+printf("%d\n", errno);
+ drmError(-errno, __FUNCTION__);
+ exit(1);
+ }
+
+ sigio_fd = fd;
+ drmInstallSIGIOHandler(fd, handler);
+ for (;;) sleep(60);
+}
+
+int main(int argc, char **argv)
+{
+ int c;
+ int r = 0;
+ int fd = -1;
+ drmHandle handle;
+ void *address;
+ char *pt;
+ unsigned long count;
+ unsigned long offset;
+ unsigned long size;
+ drmContext context;
+ int loops;
+ char buf[1024];
+ int i;
+ drmBufInfoPtr info;
+ drmBufMapPtr bufs;
+ drmLockPtr lock;
+ int secs;
+
+ while ((c = getopt(argc, argv,
+ "lc:vo:O:f:s:w:W:b:r:R:P:L:C:XS:B:F:")) != EOF)
+ switch (c) {
+ case 'F':
+ count = strtoul(optarg, NULL, 0);
+ if (!fork()) {
+ dup(fd);
+ sleep(count);
+ }
+ close(fd);
+ break;
+ case 'v': getversion(fd); break;
+ case 'X':
+ if ((r = drmCreateContext(fd, &context))) {
+ drmError(r, argv[0]);
+ return 1;
+ }
+ printf( "Got %d\n", context);
+ break;
+ case 'S':
+ process_sigio(optarg);
+ break;
+ case 'C':
+ if ((r = drmSwitchToContext(fd, strtoul(optarg, NULL, 0)))) {
+ drmError(r, argv[0]);
+ return 1;
+ }
+ break;
+ case 'c':
+ if ((r = drmSetBusid(fd,optarg))) {
+ drmError(r, argv[0]);
+ return 1;
+ }
+ break;
+ case 'o':
+ if ((fd = drmOpen(optarg, NULL)) < 0) {
+ drmError(fd, argv[0]);
+ return 1;
+ }
+ break;
+ case 'O':
+ if ((fd = drmOpen(NULL, optarg)) < 0) {
+ drmError(fd, argv[0]);
+ return 1;
+ }
+ break;
+ case 'B': /* Test buffer allocation */
+ count = strtoul(optarg, &pt, 0);
+ size = strtoul(pt+1, &pt, 0);
+ secs = strtoul(pt+1, NULL, 0);
+ {
+ drmDMAReq dma;
+ int *indices, *sizes;
+
+ indices = alloca(sizeof(*indices) * count);
+ sizes = alloca(sizeof(*sizes) * count);
+ dma.context = context;
+ dma.send_count = 0;
+ dma.request_count = count;
+ dma.request_size = size;
+ dma.request_list = indices;
+ dma.request_sizes = sizes;
+ dma.flags = DRM_DMA_WAIT;
+ if ((r = drmDMA(fd, &dma))) {
+ drmError(r, argv[0]);
+ return 1;
+ }
+ for (i = 0; i < dma.granted_count; i++) {
+ printf("%5d: index = %d, size = %d\n",
+ i, dma.request_list[i], dma.request_sizes[i]);
+ }
+ sleep(secs);
+ drmFreeBufs(fd, dma.granted_count, indices);
+ }
+ break;
+ case 'b':
+ count = strtoul(optarg, &pt, 0);
+ size = strtoul(pt+1, NULL, 0);
+ if ((r = drmAddBufs(fd, count, size, 0, 0)) < 0) {
+ drmError(r, argv[0]);
+ return 1;
+ }
+ if (!(info = drmGetBufInfo(fd))) {
+ drmError(0, argv[0]);
+ return 1;
+ }
+ for (i = 0; i < info->count; i++) {
+ printf("%5d buffers of size %6d (low = %d, high = %d)\n",
+ info->list[i].count,
+ info->list[i].size,
+ info->list[i].low_mark,
+ info->list[i].high_mark);
+ }
+ if ((r = drmMarkBufs(fd, 0.50, 0.80))) {
+ drmError(r, argv[0]);
+ return 1;
+ }
+ if (!(info = drmGetBufInfo(fd))) {
+ drmError(0, argv[0]);
+ return 1;
+ }
+ for (i = 0; i < info->count; i++) {
+ printf("%5d buffers of size %6d (low = %d, high = %d)\n",
+ info->list[i].count,
+ info->list[i].size,
+ info->list[i].low_mark,
+ info->list[i].high_mark);
+ }
+ printf("===== /proc/drm/1/meminfo =====\n");
+ sprintf(buf, "cat /proc/drm/1/meminfo");
+ system(buf);
+#if 1
+ if (!(bufs = drmMapBufs(fd))) {
+ drmError(0, argv[0]);
+ return 1;
+ }
+ printf("===============================\n");
+ printf( "%d bufs\n", bufs->count);
+ for (i = 0; i < bufs->count; i++) {
+ printf( " %4d: %8d bytes at %p\n",
+ i,
+ bufs->list[i].total,
+ bufs->list[i].address);
+ }
+ printf("===== /proc/drm/1/vmainfo =====\n");
+ sprintf(buf, "cat /proc/drm/1/vmainfo");
+ system(buf);
+#endif
+ break;
+ case 'f':
+ offset = strtoul(optarg, &pt, 0);
+ size = strtoul(pt+1, NULL, 0);
+ handle = 0;
+ if ((r = drmAddMap(fd, offset, size,
+ DRM_FRAME_BUFFER, 0, &handle))) {
+ drmError(r, argv[0]);
+ return 1;
+ }
+ printf("0x%08lx:0x%04lx added\n", offset, size);
+ printf("===== /proc/drm/1/meminfo =====\n");
+ sprintf(buf, "cat /proc/drm/1/meminfo");
+ system(buf);
+ break;
+ case 'r':
+ case 'R':
+ offset = strtoul(optarg, &pt, 0);
+ size = strtoul(pt+1, NULL, 0);
+ handle = 0;
+ if ((r = drmAddMap(fd, offset, size,
+ DRM_REGISTERS,
+ c == 'R' ? DRM_READ_ONLY : 0,
+ &handle))) {
+ drmError(r, argv[0]);
+ return 1;
+ }
+ printf("0x%08lx:0x%04lx added\n", offset, size);
+ printf("===== /proc/drm/1/meminfo =====\n");
+ sprintf(buf, "cat /proc/drm/1/meminfo");
+ system(buf);
+ break;
+ case 's':
+ size = strtoul(optarg, &pt, 0);
+ handle = 0;
+ if ((r = drmAddMap(fd, 0, size,
+ DRM_SHM, DRM_CONTAINS_LOCK,
+ &handle))) {
+ drmError(r, argv[0]);
+ return 1;
+ }
+ printf("0x%04lx byte shm added at 0x%08lx\n", size, handle);
+ sprintf(buf, "sysctl hw.graphics.0.vm");
+ system(buf);
+ break;
+ case 'P':
+ offset = strtoul(optarg, &pt, 0);
+ size = strtoul(pt+1, NULL, 0);
+ address = NULL;
+ if ((r = drmMap(fd, offset, size, &address))) {
+ drmError(r, argv[0]);
+ return 1;
+ }
+ printf("0x%08lx:0x%04lx mapped at %p for pid %d\n",
+ offset, size, address, getpid());
+ printf("===== hw.graphics.0.vma =====\n");
+ sprintf(buf, "sysctl hw.graphics.0.vma");
+ system(buf);
+ mprotect((void *)offset, size, PROT_READ);
+ printf("===== hw.graphics.0.vma =====\n");
+ sprintf(buf, "sysctl hw.graphics.0.vma");
+ system(buf);
+ break;
+ case 'w':
+ case 'W':
+ offset = strtoul(optarg, &pt, 0);
+ size = strtoul(pt+1, NULL, 0);
+ address = NULL;
+ if ((r = drmMap(fd, offset, size, &address))) {
+ drmError(r, argv[0]);
+ return 1;
+ }
+ printf("0x%08lx:0x%04lx mapped at %p for pid %d\n",
+ offset, size, address, getpid());
+ printf("===== /proc/%d/maps =====\n", getpid());
+ sprintf(buf, "cat /proc/%d/maps", getpid());
+ system(buf);
+ printf("===== /proc/drm/1/meminfo =====\n");
+ sprintf(buf, "cat /proc/drm/1/meminfo");
+ system(buf);
+ printf("===== /proc/drm/1/vmainfo =====\n");
+ sprintf(buf, "cat /proc/drm/1/vmainfo");
+ system(buf);
+ printf("===== READING =====\n");
+ for (i = 0; i < 0x10; i++)
+ printf("%02x ", (unsigned int)((unsigned char *)address)[i]);
+ printf("\n");
+ if (c == 'w') {
+ printf("===== WRITING =====\n");
+ for (i = 0; i < size; i+=2) {
+ ((char *)address)[i] = i & 0xff;
+ ((char *)address)[i+1] = i & 0xff;
+ }
+ }
+ printf("===== READING =====\n");
+ for (i = 0; i < 0x10; i++)
+ printf("%02x ", (unsigned int)((unsigned char *)address)[i]);
+ printf("\n");
+ printf("===== /proc/drm/1/vmainfo =====\n");
+ sprintf(buf, "cat /proc/drm/1/vmainfo");
+ system(buf);
+ break;
+ case 'L':
+ context = strtoul(optarg, &pt, 0);
+ offset = strtoul(pt+1, &pt, 0);
+ size = strtoul(pt+1, &pt, 0);
+ loops = strtoul(pt+1, NULL, 0);
+ address = NULL;
+ if ((r = drmMap(fd, offset, size, &address))) {
+ drmError(r, argv[0]);
+ return 1;
+ }
+ lock = address;
+#if 1
+ {
+ int counter = 0;
+ struct timeval loop_start, loop_end;
+ struct timeval lock_start, lock_end;
+ double wt;
+#define HISTOSIZE 9
+ int histo[HISTOSIZE];
+ int output = 0;
+ int fast = 0;
+
+ if (loops < 0) {
+ loops = -loops;
+ ++output;
+ }
+
+ for (i = 0; i < HISTOSIZE; i++) histo[i] = 0;
+
+ gettimeofday(&loop_start, NULL);
+ for (i = 0; i < loops; i++) {
+ gettimeofday(&lock_start, NULL);
+ DRM_LIGHT_LOCK_COUNT(fd,lock,context,fast);
+ gettimeofday(&lock_end, NULL);
+ DRM_UNLOCK(fd,lock,context);
+ ++counter;
+ wt = usec(&lock_end, &lock_start);
+ if (wt <= 2.5) ++histo[8];
+ if (wt < 5.0) ++histo[0];
+ else if (wt < 50.0) ++histo[1];
+ else if (wt < 500.0) ++histo[2];
+ else if (wt < 5000.0) ++histo[3];
+ else if (wt < 50000.0) ++histo[4];
+ else if (wt < 500000.0) ++histo[5];
+ else if (wt < 5000000.0) ++histo[6];
+ else ++histo[7];
+ if (output) printf( "%.2f uSec, %d fast\n", wt, fast);
+ }
+ gettimeofday(&loop_end, NULL);
+ printf( "Average wait time = %.2f usec, %d fast\n",
+ usec(&loop_end, &loop_start) / counter, fast);
+ printf( "%9d <= 2.5 uS\n", histo[8]);
+ printf( "%9d < 5 uS\n", histo[0]);
+ printf( "%9d < 50 uS\n", histo[1]);
+ printf( "%9d < 500 uS\n", histo[2]);
+ printf( "%9d < 5000 uS\n", histo[3]);
+ printf( "%9d < 50000 uS\n", histo[4]);
+ printf( "%9d < 500000 uS\n", histo[5]);
+ printf( "%9d < 5000000 uS\n", histo[6]);
+ printf( "%9d >= 5000000 uS\n", histo[7]);
+ }
+#else
+ printf( "before lock: 0x%08x\n", lock->lock);
+ printf( "lock: 0x%08x\n", lock->lock);
+ sleep(5);
+ printf( "unlock: 0x%08x\n", lock->lock);
+#endif
+ break;
+ default:
+ fprintf( stderr, "Usage: drmstat [options]\n" );
+ return 1;
+ }
+
+ return r;
+}
diff --git a/bsd/drm/fops.c b/bsd/drm/fops.c
new file mode 100644
index 00000000..837fc7db
--- /dev/null
+++ b/bsd/drm/fops.c
@@ -0,0 +1,260 @@
+/* fops.c -- File operations for DRM -*- c -*-
+ * Created: Mon Jan 4 08:58:31 1999 by faith@precisioninsight.com
+ * Revised: Tue Oct 12 08:48:59 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/fops.c,v 1.3 1999/08/20 15:36:45 faith Exp $
+ * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/fops.c,v 1.1 1999/09/25 14:37:59 dawes Exp $
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+#include <sys/signalvar.h>
+#include <sys/poll.h>
+
+drm_file_t *drm_find_file_by_proc(drm_device_t *dev, struct proc *p)
+{
+ uid_t uid = p->p_cred->p_svuid;
+ pid_t pid = p->p_pid;
+ drm_file_t *priv;
+
+ TAILQ_FOREACH(priv, &dev->files, link)
+ if (priv->pid == pid && priv->uid == uid)
+ return priv;
+ return NULL;
+}
+
+
+/* drm_open is called whenever a process opens /dev/drm. */
+
+int drm_open_helper(dev_t kdev, int flags, int fmt, struct proc *p,
+ drm_device_t *dev)
+{
+ int m = minor(kdev);
+ drm_file_t *priv;
+
+ if (flags & O_EXCL)
+ return EBUSY; /* No exclusive opens */
+
+ dev->flags = flags;
+
+ DRM_DEBUG("pid = %d, device = %p, minor = %d\n",
+ p->p_pid, dev->device, m);
+
+ priv = drm_find_file_by_proc(dev, p);
+ if (priv) {
+ priv->refs++;
+ } else {
+ priv = drm_alloc(sizeof(*priv), DRM_MEM_FILES);
+ memset(priv, 0, sizeof(*priv));
+ priv->uid = p->p_cred->p_svuid;
+ priv->pid = p->p_pid;
+ priv->refs = 1;
+ priv->minor = m;
+ priv->devXX = dev;
+ priv->ioctl_count = 0;
+ priv->authenticated = !suser(p);
+ lockmgr(&dev->dev_lock, LK_EXCLUSIVE, 0, p);
+ TAILQ_INSERT_TAIL(&dev->files, priv, link);
+ lockmgr(&dev->dev_lock, LK_RELEASE, 0, p);
+ }
+
+ kdev->si_drv1 = dev;
+
+ return 0;
+}
+
+int drm_write(dev_t kdev, struct uio *uio, int ioflag)
+{
+ struct proc *p = curproc;
+ drm_device_t *dev = kdev->si_drv1;
+
+ DRM_DEBUG("pid = %d, device = %p, open_count = %d\n",
+ p->p_pid, dev->device, dev->open_count);
+ return 0;
+}
+
+/* drm_release is called whenever a process closes /dev/drm*. */
+
+int drm_close(dev_t kdev, int fflag, int devtype, struct proc *p)
+{
+ drm_device_t *dev = kdev->si_drv1;
+ drm_file_t *priv;
+
+ DRM_DEBUG("pid = %d, device = %p, open_count = %d\n",
+ p->p_pid, dev->device, dev->open_count);
+
+ priv = drm_find_file_by_proc(dev, p);
+ if (!priv) {
+ DRM_DEBUG("can't find authenticator\n");
+ return EINVAL;
+ }
+
+ if (dev->lock.hw_lock && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)
+ && dev->lock.pid == p->p_pid) {
+ DRM_ERROR("Process %d dead, freeing lock for context %d\n",
+ p->p_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. */
+ }
+ drm_reclaim_buffers(dev, priv->pid);
+
+ funsetown(dev->buf_sigio);
+
+ lockmgr(&dev->dev_lock, LK_EXCLUSIVE, 0, p);
+ priv = drm_find_file_by_proc(dev, p);
+ if (priv) {
+ priv->refs--;
+ if (!priv->refs) {
+ TAILQ_REMOVE(&dev->files, priv, link);
+ drm_free(priv, sizeof(*priv), DRM_MEM_FILES);
+ }
+ }
+ lockmgr(&dev->dev_lock, LK_RELEASE, 0, p);
+
+ return 0;
+}
+
+/* The drm_read and drm_write_string code (especially that which manages
+ the circular buffer), is based on Alessandro Rubini's LINUX DEVICE
+ DRIVERS (Cambridge: O'Reilly, 1998), pages 111-113. */
+
+ssize_t drm_read(dev_t kdev, struct uio *uio, int ioflag)
+{
+ drm_device_t *dev = kdev->si_drv1;
+ int left;
+ int avail;
+ int send;
+ int cur;
+ int error = 0;
+
+ DRM_DEBUG("%p, %p\n", dev->buf_rp, dev->buf_wp);
+
+ while (dev->buf_rp == dev->buf_wp) {
+ DRM_DEBUG(" sleeping\n");
+ if (dev->flags & FASYNC) {
+ return EWOULDBLOCK;
+ }
+ error = tsleep(&dev->buf_rp, PZERO|PCATCH, "drmrd", 0);
+ if (error) {
+ DRM_DEBUG(" interrupted\n");
+ return error;
+ }
+ DRM_DEBUG(" awake\n");
+ }
+
+ left = (dev->buf_rp + DRM_BSZ - dev->buf_wp) % DRM_BSZ;
+ avail = DRM_BSZ - left;
+ send = DRM_MIN(avail, uio->uio_resid);
+
+ while (send) {
+ if (dev->buf_wp > dev->buf_rp) {
+ cur = DRM_MIN(send, dev->buf_wp - dev->buf_rp);
+ } else {
+ cur = DRM_MIN(send, dev->buf_end - dev->buf_rp);
+ }
+ error = uiomove(dev->buf_rp, cur, uio);
+ if (error)
+ break;
+ dev->buf_rp += cur;
+ if (dev->buf_rp == dev->buf_end) dev->buf_rp = dev->buf;
+ send -= cur;
+ }
+
+ wakeup(&dev->buf_wp);
+
+ return error;
+}
+
+int drm_write_string(drm_device_t *dev, const char *s)
+{
+ int left = (dev->buf_rp + DRM_BSZ - dev->buf_wp) % DRM_BSZ;
+ int send = strlen(s);
+ int count;
+
+ DRM_DEBUG("%d left, %d to send (%p, %p)\n",
+ left, send, dev->buf_rp, dev->buf_wp);
+
+ if (left == 1 || dev->buf_wp != dev->buf_rp) {
+ DRM_ERROR("Buffer not empty (%d left, wp = %p, rp = %p)\n",
+ left,
+ dev->buf_wp,
+ dev->buf_rp);
+ }
+
+ while (send) {
+ if (dev->buf_wp >= dev->buf_rp) {
+ count = DRM_MIN(send, dev->buf_end - dev->buf_wp);
+ if (count == left) --count; /* Leave a hole */
+ } else {
+ count = DRM_MIN(send, dev->buf_rp - dev->buf_wp - 1);
+ }
+ strncpy(dev->buf_wp, s, count);
+ dev->buf_wp += count;
+ if (dev->buf_wp == dev->buf_end) dev->buf_wp = dev->buf;
+ send -= count;
+ }
+
+ if (dev->buf_selecting) {
+ dev->buf_selecting = 0;
+ selwakeup(&dev->buf_sel);
+ }
+
+ DRM_DEBUG("dev->buf_sigio=%p\n", dev->buf_sigio);
+ if (dev->buf_sigio) {
+ DRM_DEBUG("dev->buf_sigio->sio_pgid=%d\n", dev->buf_sigio->sio_pgid);
+ pgsigio(dev->buf_sigio, SIGIO, 0);
+ }
+
+ DRM_DEBUG("waking\n");
+ wakeup(&dev->buf_rp);
+ return 0;
+}
+
+int drm_poll(dev_t kdev, int events, struct proc *p)
+{
+ drm_device_t *dev = kdev->si_drv1;
+ int s;
+ int revents = 0;
+
+ s = spldrm();
+ if (events & (POLLIN | POLLRDNORM)) {
+ int left = (dev->buf_rp + DRM_BSZ - dev->buf_wp) % DRM_BSZ;
+ if (left > 0)
+ revents |= events & (POLLIN | POLLRDNORM);
+ else
+ selrecord(p, &dev->buf_sel);
+ }
+ splx(s);
+
+ return revents;
+}
diff --git a/bsd/drm/init.c b/bsd/drm/init.c
new file mode 100644
index 00000000..44e9be99
--- /dev/null
+++ b/bsd/drm/init.c
@@ -0,0 +1,101 @@
+/* init.c -- Setup/Cleanup for DRM -*- c -*-
+ * Created: Mon Jan 4 08:58:31 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 09:27:02 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/init.c,v 1.3 1999/08/20 15:07:01 faith Exp $
+ * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/init.c,v 1.1 1999/09/25 14:38:01 dawes Exp $
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+MODULE_VERSION(drm, 1);
+
+int drm_flags = 0;
+
+/* drm_parse_option parses a single option. See description for
+ drm_parse_drm for details. */
+
+static void drm_parse_option(char *s)
+{
+ char *c, *r;
+
+ DRM_DEBUG("\"%s\"\n", s);
+ if (!s || !*s) return;
+ for (c = s; *c && *c != ':'; c++); /* find : or \0 */
+ if (*c) r = c + 1; else r = NULL; /* remember remainder */
+ *c = '\0'; /* terminate */
+ if (!strcmp(s, "noctx")) {
+ drm_flags |= DRM_FLAG_NOCTX;
+ DRM_INFO("Server-mediated context switching OFF\n");
+ return;
+ }
+ if (!strcmp(s, "debug")) {
+ drm_flags |= DRM_FLAG_DEBUG;
+ DRM_INFO("Debug messages ON\n");
+ return;
+ }
+ DRM_ERROR("\"%s\" is not a valid option\n", s);
+ return;
+}
+
+/* drm_parse_options parse the insmod "drm=" options, or the command-line
+ * options passed to the kernel via LILO. The grammar of the format is as
+ * follows:
+ *
+ * drm ::= 'drm=' option_list
+ * option_list ::= option [ ';' option_list ]
+ * option ::= 'device:' major
+ * | 'debug'
+ * | 'noctx'
+ * major ::= INTEGER
+ *
+ * Note that 's' contains option_list without the 'drm=' part.
+ *
+ * device=major,minor specifies the device number used for /dev/drm
+ * if major == 0 then the misc device is used
+ * if major == 0 and minor == 0 then dynamic misc allocation is used
+ * debug=on specifies that debugging messages will be printk'd
+ * debug=trace specifies that each function call will be logged via printk
+ * debug=off turns off all debugging options
+ *
+ */
+
+void drm_parse_options(char *s)
+{
+ char *h, *t, *n;
+
+ DRM_DEBUG("\"%s\"\n", s ?: "");
+ if (!s || !*s) return;
+
+ for (h = t = n = s; h && *h; h = n) {
+ for (; *t && *t != ';'; t++); /* find ; or \0 */
+ if (*t) n = t + 1; else n = NULL; /* remember next */
+ *t = '\0'; /* terminate */
+ drm_parse_option(h); /* parse */
+ }
+}
+
diff --git a/bsd/drm/ioctl.c b/bsd/drm/ioctl.c
new file mode 100644
index 00000000..55bdeeda
--- /dev/null
+++ b/bsd/drm/ioctl.c
@@ -0,0 +1,120 @@
+/* ioctl.c -- IOCTL processing for DRM -*- c -*-
+ * Created: Fri Jan 8 09:01:26 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 09:27:02 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/ioctl.c,v 1.3 1999/08/30 13:05:00 faith Exp $
+ * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/ioctl.c,v 1.1 1999/09/25 14:38:01 dawes Exp $
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+#include <sys/bus.h>
+#include <pci/pcivar.h>
+
+int
+drm_irq_busid(dev_t kdev, u_long cmd, caddr_t data, int flags, struct proc *p)
+{
+ drm_irq_busid_t id;
+ devclass_t pci;
+ device_t bus, dev;
+ device_t *kids;
+ int error, i, num_kids;
+
+ id = *(drm_irq_busid_t *) data;
+ pci = devclass_find("pci");
+ if (!pci)
+ return ENOENT;
+ bus = devclass_get_device(pci, id.busnum);
+ if (!bus)
+ return ENOENT;
+ error = device_get_children(bus, &kids, &num_kids);
+ if (error)
+ return error;
+
+ dev = 0;
+ for (i = 0; i < num_kids; i++) {
+ dev = kids[i];
+ if (pci_get_slot(dev) == id.devnum
+ && pci_get_function(dev) == id.funcnum)
+ break;
+ }
+
+ free(kids, M_TEMP);
+
+ if (i != num_kids)
+ id.irq = pci_get_irq(dev);
+ else
+ id.irq = 0;
+
+ DRM_DEBUG("%d:%d:%d => IRQ %d\n",
+ id.busnum, id.devnum, id.funcnum, id.irq);
+ *(drm_irq_busid_t *) data = id;
+
+ return 0;
+}
+
+int
+drm_getunique(dev_t kdev, u_long cmd, caddr_t data, int flags, struct proc *p)
+{
+ drm_device_t *dev = kdev->si_drv1;
+ drm_unique_t u;
+ int error;
+
+ u = *(drm_unique_t *) data;
+ if (u.unique_len >= dev->unique_len) {
+ error = copyout(dev->unique, u.unique, dev->unique_len);
+ if (error)
+ return error;
+ }
+ u.unique_len = dev->unique_len;
+ *(drm_unique_t *) data = u;
+ return 0;
+}
+
+int
+drm_setunique(dev_t kdev, u_long cmd, caddr_t data, int flags, struct proc *p)
+{
+ drm_device_t *dev = kdev->si_drv1;
+ drm_unique_t u;
+ int error;
+
+ if (dev->unique_len || dev->unique) return EBUSY;
+
+ u = *(drm_unique_t *) data;
+
+ dev->unique_len = u.unique_len;
+ dev->unique = drm_alloc(u.unique_len + 1, DRM_MEM_DRIVER);
+ error = copyin(u.unique, dev->unique, dev->unique_len);
+ if (error)
+ return error;
+ dev->unique[dev->unique_len] = '\0';
+
+ dev->devname = drm_alloc(strlen(dev->name) + strlen(dev->unique) + 2,
+ DRM_MEM_DRIVER);
+ sprintf(dev->devname, "%s@%s", dev->name, dev->unique);
+
+ return 0;
+}
diff --git a/bsd/drm/lists.c b/bsd/drm/lists.c
new file mode 100644
index 00000000..9f9b5f7a
--- /dev/null
+++ b/bsd/drm/lists.c
@@ -0,0 +1,258 @@
+/* lists.c -- Buffer list handling routines -*- c -*-
+ * Created: Mon Apr 19 20:54:22 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 09:27:01 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/lists.c,v 1.3 1999/08/20 15:07:02 faith Exp $
+ * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/lists.c,v 1.1 1999/09/25 14:38:01 dawes Exp $
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+int drm_waitlist_create(drm_waitlist_t *bl, int count)
+{
+ DRM_DEBUG("%d\n", count);
+ if (bl->count) return EINVAL;
+
+ bl->count = count;
+ bl->bufs = drm_alloc((bl->count + 2) * sizeof(*bl->bufs),
+ DRM_MEM_BUFLISTS);
+ bl->rp = bl->bufs;
+ bl->wp = bl->bufs;
+ bl->end = &bl->bufs[bl->count+1];
+ simple_lock_init(&bl->write_lock);
+ simple_lock_init(&bl->read_lock);
+ return 0;
+}
+
+int drm_waitlist_destroy(drm_waitlist_t *bl)
+{
+ DRM_DEBUG("\n");
+ if (bl->rp != bl->wp) return EINVAL;
+ if (bl->bufs) drm_free(bl->bufs,
+ (bl->count + 2) * sizeof(*bl->bufs),
+ DRM_MEM_BUFLISTS);
+ bl->count = 0;
+ bl->bufs = NULL;
+ bl->rp = NULL;
+ bl->wp = NULL;
+ bl->end = NULL;
+ return 0;
+}
+
+int drm_waitlist_put(drm_waitlist_t *bl, drm_buf_t *buf)
+{
+ int left;
+ int s;
+
+ left = DRM_LEFTCOUNT(bl);
+ DRM_DEBUG("put %d (%d left, rp = %p, wp = %p)\n",
+ buf->idx, left, bl->rp, bl->wp);
+ if (!left) {
+ DRM_ERROR("Overflow while adding buffer %d from pid %d\n",
+ buf->idx, buf->pid);
+ return EINVAL;
+ }
+#if DRM_DMA_HISTOGRAM
+ getnanotime(&buf->time_queued);
+#endif
+ buf->list = DRM_LIST_WAIT;
+
+ simple_lock(&bl->write_lock);
+ s = spldrm();
+ *bl->wp = buf;
+ if (++bl->wp >= bl->end) bl->wp = bl->bufs;
+ splx(s);
+ simple_unlock(&bl->write_lock);
+
+ return 0;
+}
+
+drm_buf_t *drm_waitlist_get(drm_waitlist_t *bl)
+{
+ drm_buf_t *buf;
+ int s;
+
+ simple_lock(&bl->read_lock);
+ s = spldrm();
+ buf = *bl->rp;
+ if (bl->rp == bl->wp) {
+ splx(s);
+ simple_unlock(&bl->read_lock);
+ return NULL;
+ }
+ if (++bl->rp >= bl->end) bl->rp = bl->bufs;
+ splx(s);
+ simple_unlock(&bl->read_lock);
+
+ DRM_DEBUG("get %d\n", buf->idx);
+ return buf;
+}
+
+int drm_freelist_create(drm_freelist_t *bl, int count)
+{
+ DRM_DEBUG("\n");
+ atomic_set(&bl->count, 0);
+ bl->next = NULL;
+ bl->waiting = 0;
+ bl->low_mark = 0;
+ bl->high_mark = 0;
+ atomic_set(&bl->wfh, 0);
+ ++bl->initialized;
+ return 0;
+}
+
+int drm_freelist_destroy(drm_freelist_t *bl)
+{
+ DRM_DEBUG("\n");
+ atomic_set(&bl->count, 0);
+ bl->next = NULL;
+ return 0;
+}
+
+int drm_freelist_put(drm_device_t *dev, drm_freelist_t *bl, drm_buf_t *buf)
+{
+ unsigned int old;
+ unsigned int new;
+ char failed;
+ int count = 0;
+ drm_device_dma_t *dma = dev->dma;
+
+ if (!dma) {
+ DRM_ERROR("No DMA support\n");
+ return 1;
+ }
+
+ if (buf->waiting || buf->pending || buf->list == DRM_LIST_FREE) {
+ DRM_ERROR("Freed buffer %d: w%d, p%d, l%d\n",
+ buf->idx, buf->waiting, buf->pending, buf->list);
+ }
+ DRM_DEBUG("%d, count = %d, wfh = %d, w%d, p%d\n",
+ buf->idx, atomic_read(&bl->count), atomic_read(&bl->wfh),
+ buf->waiting, buf->pending);
+ if (!bl) return 1;
+#if DRM_DMA_HISTOGRAM
+ getnanotime(&buf->time_freed);
+ drm_histogram_compute(dev, buf);
+#endif
+ buf->list = DRM_LIST_FREE;
+ do {
+ old = (unsigned long)bl->next;
+ buf->next = (void *)old;
+ new = (unsigned long)buf;
+ _DRM_CAS(&bl->next, old, new, failed);
+ if (++count > DRM_LOOPING_LIMIT) {
+ DRM_ERROR("Looping\n");
+ return 1;
+ }
+ } while (failed);
+ atomic_inc(&bl->count);
+ if (atomic_read(&bl->count) > dma->buf_count) {
+ DRM_ERROR("%d of %d buffers free after addition of %d\n",
+ atomic_read(&bl->count), dma->buf_count, buf->idx);
+ return 1;
+ }
+ /* Check for high water mark */
+ if (atomic_read(&bl->wfh) && atomic_read(&bl->count)>=bl->high_mark) {
+ atomic_set(&bl->wfh, 0);
+ if (bl->waiting)
+ wakeup(&bl->waiting);
+ }
+ return 0;
+}
+
+static drm_buf_t *drm_freelist_try(drm_freelist_t *bl)
+{
+ unsigned int old;
+ unsigned int new;
+ char failed;
+ drm_buf_t *buf;
+ int count = 0;
+
+ if (!bl) return NULL;
+
+ /* Get buffer */
+ do {
+ old = (unsigned int)bl->next;
+ if (!old) {
+ return NULL;
+ }
+ new = (unsigned long)bl->next->next;
+ _DRM_CAS(&bl->next, old, new, failed);
+ if (++count > DRM_LOOPING_LIMIT) {
+ DRM_ERROR("Looping\n");
+ return NULL;
+ }
+ } while (failed);
+ atomic_dec(&bl->count);
+
+ buf = (drm_buf_t *)old;
+ buf->next = NULL;
+ buf->list = DRM_LIST_NONE;
+ DRM_DEBUG("%d, count = %d, wfh = %d, w%d, p%d\n",
+ buf->idx, atomic_read(&bl->count), atomic_read(&bl->wfh),
+ buf->waiting, buf->pending);
+ if (buf->waiting || buf->pending) {
+ DRM_ERROR("Free buffer %d: w%d, p%d, l%d\n",
+ buf->idx, buf->waiting, buf->pending, buf->list);
+ }
+
+ return buf;
+}
+
+drm_buf_t *drm_freelist_get(drm_freelist_t *bl, int block)
+{
+ drm_buf_t *buf = NULL;
+ int error;
+
+ if (!bl || !bl->initialized) return NULL;
+
+ /* Check for low water mark */
+ if (atomic_read(&bl->count) <= bl->low_mark) /* Became low */
+ atomic_set(&bl->wfh, 1);
+ if (atomic_read(&bl->wfh)) {
+ DRM_DEBUG("Block = %d, count = %d, wfh = %d\n",
+ block, atomic_read(&bl->count),
+ atomic_read(&bl->wfh));
+ if (block) {
+ atomic_inc(&bl->waiting);
+ for (;;) {
+ if (!atomic_read(&bl->wfh)
+ && (buf = drm_freelist_try(bl))) break;
+ error = tsleep(&bl->waiting, PZERO|PCATCH,
+ "drmfg", 0);
+ if (error)
+ break;
+ }
+ atomic_dec(&bl->waiting);
+ }
+ return buf;
+ }
+
+ DRM_DEBUG("Count = %d, wfh = %d\n",
+ atomic_read(&bl->count), atomic_read(&bl->wfh));
+ return drm_freelist_try(bl);
+}
diff --git a/bsd/drm/lock.c b/bsd/drm/lock.c
new file mode 100644
index 00000000..cd14a882
--- /dev/null
+++ b/bsd/drm/lock.c
@@ -0,0 +1,220 @@
+/* lock.c -- IOCTLs for locking -*- c -*-
+ * Created: Tue Feb 2 08:37:54 1999 by faith@precisioninsight.com
+ * Revised: Tue Oct 12 08:51:06 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/lock.c,v 1.5 1999/08/30 13:05:00 faith Exp $
+ * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/lock.c,v 1.1 1999/09/25 14:38:01 dawes Exp $
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+int
+drm_block(dev_t kdev, u_long cmd, caddr_t data, int flags, struct proc *p)
+{
+ DRM_DEBUG("\n");
+ return 0;
+}
+
+int
+drm_unblock(dev_t kdev, u_long cmd, caddr_t data, int flags, struct proc *p)
+{
+ DRM_DEBUG("\n");
+ return 0;
+}
+
+int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context)
+{
+ unsigned int old;
+ unsigned int new;
+ char failed;
+
+ DRM_DEBUG("%d attempts\n", context);
+ do {
+ old = *lock;
+ if (old & _DRM_LOCK_HELD) new = old | _DRM_LOCK_CONT;
+ else new = context | _DRM_LOCK_HELD;
+ _DRM_CAS(lock, old, new, failed);
+ } while (failed);
+ if (_DRM_LOCKING_CONTEXT(old) == context) {
+ if (old & _DRM_LOCK_HELD) {
+ if (context != DRM_KERNEL_CONTEXT) {
+ DRM_ERROR("%d holds heavyweight lock\n",
+ context);
+ }
+ return 0;
+ }
+ }
+ if (new == (context | _DRM_LOCK_HELD)) {
+ /* Have lock */
+ DRM_DEBUG("%d\n", context);
+ return 1;
+ }
+ DRM_DEBUG("%d unable to get lock held by %d\n",
+ context, _DRM_LOCKING_CONTEXT(old));
+ return 0;
+}
+
+/* This takes a lock forcibly and hands it to context. Should ONLY be used
+ inside *_unlock to give lock to kernel before calling *_dma_schedule. */
+int drm_lock_transfer(drm_device_t *dev,
+ __volatile__ unsigned int *lock, unsigned int context)
+{
+ unsigned int old;
+ unsigned int new;
+ char failed;
+
+ dev->lock.pid = 0;
+ do {
+ old = *lock;
+ new = context | _DRM_LOCK_HELD;
+ _DRM_CAS(lock, old, new, failed);
+ } while (failed);
+ DRM_DEBUG("%d => %d\n", _DRM_LOCKING_CONTEXT(old), context);
+ return 1;
+}
+
+int drm_lock_free(drm_device_t *dev,
+ __volatile__ unsigned int *lock, unsigned int context)
+{
+ unsigned int old;
+ unsigned int new;
+ char failed;
+ pid_t pid = dev->lock.pid;
+
+ DRM_DEBUG("%d\n", context);
+ dev->lock.pid = 0;
+ do {
+ old = *lock;
+ new = 0;
+ _DRM_CAS(lock, old, new, failed);
+ } while (failed);
+ if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) {
+ DRM_ERROR("%d freed heavyweight lock held by %d (pid %d)\n",
+ context,
+ _DRM_LOCKING_CONTEXT(old),
+ pid);
+ return 1;
+ }
+ wakeup(&dev->lock.lock_queue);
+ return 0;
+}
+
+static int drm_flush_queue(drm_device_t *dev, int context)
+{
+ int ret = 0;
+ int error;
+ drm_queue_t *q = dev->queuelist[context];
+
+ DRM_DEBUG("\n");
+
+ atomic_inc(&q->use_count);
+ if (atomic_read(&q->use_count) > 1) {
+ atomic_inc(&q->block_write);
+ atomic_inc(&q->block_count);
+ error = tsleep(&q->flush_queue, PCATCH|PZERO, "drmfq", 0);
+ if (error)
+ return error;
+ atomic_dec(&q->block_count);
+ }
+ atomic_dec(&q->use_count);
+ atomic_inc(&q->total_flushed);
+
+ /* NOTE: block_write is still incremented!
+ Use drm_flush_unlock_queue to decrement. */
+ return ret;
+}
+
+static int drm_flush_unblock_queue(drm_device_t *dev, int context)
+{
+ drm_queue_t *q = dev->queuelist[context];
+
+ DRM_DEBUG("\n");
+
+ atomic_inc(&q->use_count);
+ if (atomic_read(&q->use_count) > 1) {
+ if (atomic_read(&q->block_write)) {
+ atomic_dec(&q->block_write);
+ wakeup(&q->write_queue);
+ }
+ }
+ atomic_dec(&q->use_count);
+ return 0;
+}
+
+int drm_flush_block_and_flush(drm_device_t *dev, int context,
+ drm_lock_flags_t flags)
+{
+ int ret = 0;
+ int i;
+
+ DRM_DEBUG("\n");
+
+ if (flags & _DRM_LOCK_FLUSH) {
+ ret = drm_flush_queue(dev, DRM_KERNEL_CONTEXT);
+ if (!ret) ret = drm_flush_queue(dev, context);
+ }
+ if (flags & _DRM_LOCK_FLUSH_ALL) {
+ for (i = 0; !ret && i < dev->queue_count; i++) {
+ ret = drm_flush_queue(dev, i);
+ }
+ }
+ return ret;
+}
+
+int drm_flush_unblock(drm_device_t *dev, int context, drm_lock_flags_t flags)
+{
+ int ret = 0;
+ int i;
+
+ DRM_DEBUG("\n");
+
+ if (flags & _DRM_LOCK_FLUSH) {
+ ret = drm_flush_unblock_queue(dev, DRM_KERNEL_CONTEXT);
+ if (!ret) ret = drm_flush_unblock_queue(dev, context);
+ }
+ if (flags & _DRM_LOCK_FLUSH_ALL) {
+ for (i = 0; !ret && i < dev->queue_count; i++) {
+ ret = drm_flush_unblock_queue(dev, i);
+ }
+ }
+
+ return ret;
+}
+
+int drm_finish(dev_t kdev, u_long cmd, caddr_t data, int flags, struct proc *p)
+{
+ drm_device_t *dev = kdev->si_drv1;
+ int ret = 0;
+ drm_lock_t lock;
+
+ DRM_DEBUG("\n");
+
+ lock = *(drm_lock_t *) data;
+ ret = drm_flush_block_and_flush(dev, lock.context, lock.flags);
+ drm_flush_unblock(dev, lock.context, lock.flags);
+ return ret;
+}
diff --git a/bsd/drm/memory.c b/bsd/drm/memory.c
new file mode 100644
index 00000000..a8a936df
--- /dev/null
+++ b/bsd/drm/memory.c
@@ -0,0 +1,458 @@
+/* memory.c -- Memory management wrappers for DRM -*- c -*-
+ * Created: Thu Feb 4 14:00:34 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 13:04:33 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/memory.c,v 1.4 1999/08/20 20:00:53 faith Exp $
+ * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/memory.c,v 1.1 1999/09/25 14:38:02 dawes Exp $
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#ifdef DRM_AGP
+#include <sys/agpio.h>
+#endif
+
+MALLOC_DEFINE(M_DRM, "drm", "DRM Data Structures");
+
+typedef struct drm_mem_stats {
+ const char *name;
+ int succeed_count;
+ int free_count;
+ int fail_count;
+ unsigned long bytes_allocated;
+ unsigned long bytes_freed;
+} drm_mem_stats_t;
+
+#ifdef SMP
+static struct simplelock drm_mem_lock;
+#endif
+static unsigned long drm_ram_available = 0;
+static unsigned long drm_ram_used = 0;
+static drm_mem_stats_t drm_mem_stats[] = {
+ [DRM_MEM_DMA] = { "dmabufs" },
+ [DRM_MEM_SAREA] = { "sareas" },
+ [DRM_MEM_DRIVER] = { "driver" },
+ [DRM_MEM_MAGIC] = { "magic" },
+ [DRM_MEM_IOCTLS] = { "ioctltab" },
+ [DRM_MEM_MAPS] = { "maplist" },
+ [DRM_MEM_VMAS] = { "vmalist" },
+ [DRM_MEM_BUFS] = { "buflist" },
+ [DRM_MEM_SEGS] = { "seglist" },
+ [DRM_MEM_PAGES] = { "pagelist" },
+ [DRM_MEM_FILES] = { "files" },
+ [DRM_MEM_QUEUES] = { "queues" },
+ [DRM_MEM_CMDS] = { "commands" },
+ [DRM_MEM_MAPPINGS] = { "mappings" },
+ [DRM_MEM_BUFLISTS] = { "buflists" },
+ [DRM_MEM_AGPLISTS] = { "agplist" },
+ [DRM_MEM_TOTALAGP] = { "totalagp" },
+ [DRM_MEM_BOUNDAGP] = { "boundagp" },
+ [DRM_MEM_CTXBITMAP] = { "ctxbitmap"},
+ { NULL, 0, } /* Last entry must be null */
+};
+
+void drm_mem_init(void)
+{
+ drm_mem_stats_t *mem;
+
+ for (mem = drm_mem_stats; mem->name; ++mem) {
+ mem->succeed_count = 0;
+ mem->free_count = 0;
+ mem->fail_count = 0;
+ mem->bytes_allocated = 0;
+ mem->bytes_freed = 0;
+ }
+
+ drm_ram_available = 0; /* si.totalram; */
+ drm_ram_used = 0;
+}
+
+/* drm_mem_info is called whenever a process reads /dev/drm/mem. */
+
+static int _drm_mem_info SYSCTL_HANDLER_ARGS
+{
+ drm_mem_stats_t *pt;
+ char buf[128];
+ int error;
+
+ DRM_SYSCTL_PRINT(" total counts "
+ " | outstanding \n");
+ DRM_SYSCTL_PRINT("type alloc freed fail bytes freed"
+ " | allocs bytes\n\n");
+ DRM_SYSCTL_PRINT("%-9.9s %5d %5d %4d %10lu |\n",
+ "system", 0, 0, 0, drm_ram_available);
+ DRM_SYSCTL_PRINT("%-9.9s %5d %5d %4d %10lu |\n",
+ "locked", 0, 0, 0, drm_ram_used);
+ DRM_SYSCTL_PRINT("\n");
+ for (pt = drm_mem_stats; pt->name; pt++) {
+ DRM_SYSCTL_PRINT("%-9.9s %5d %5d %4d %10lu %10lu | %6d %10ld\n",
+ pt->name,
+ pt->succeed_count,
+ pt->free_count,
+ pt->fail_count,
+ pt->bytes_allocated,
+ pt->bytes_freed,
+ pt->succeed_count - pt->free_count,
+ (long)pt->bytes_allocated
+ - (long)pt->bytes_freed);
+ }
+ SYSCTL_OUT(req, "", 1);
+
+ return 0;
+}
+
+int drm_mem_info SYSCTL_HANDLER_ARGS
+{
+ int ret;
+
+ simple_lock(&drm_mem_lock);
+ ret = _drm_mem_info(oidp, arg1, arg2, req);
+ simple_unlock(&drm_mem_lock);
+ return ret;
+}
+
+void *drm_alloc(size_t size, int area)
+{
+ void *pt;
+
+ if (!size) {
+ DRM_MEM_ERROR(area, "Allocating 0 bytes\n");
+ return NULL;
+ }
+
+ if (!(pt = malloc(size, M_DRM, M_NOWAIT))) {
+ simple_lock(&drm_mem_lock);
+ ++drm_mem_stats[area].fail_count;
+ simple_unlock(&drm_mem_lock);
+ return NULL;
+ }
+ simple_lock(&drm_mem_lock);
+ ++drm_mem_stats[area].succeed_count;
+ drm_mem_stats[area].bytes_allocated += size;
+ simple_unlock(&drm_mem_lock);
+ return pt;
+}
+
+void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area)
+{
+ void *pt;
+
+ if (!(pt = drm_alloc(size, area))) return NULL;
+ if (oldpt && oldsize) {
+ memcpy(pt, oldpt, oldsize);
+ drm_free(oldpt, oldsize, area);
+ }
+ return pt;
+}
+
+char *drm_strdup(const char *s, int area)
+{
+ char *pt;
+ int length = s ? strlen(s) : 0;
+
+ if (!(pt = drm_alloc(length+1, area))) return NULL;
+ strcpy(pt, s);
+ return pt;
+}
+
+void drm_strfree(char *s, int area)
+{
+ unsigned int size;
+
+ if (!s) return;
+
+ size = 1 + (s ? strlen(s) : 0);
+ drm_free((void *)s, size, area);
+}
+
+void drm_free(void *pt, size_t size, int area)
+{
+ int alloc_count;
+ int free_count;
+
+ if (!pt) DRM_MEM_ERROR(area, "Attempt to free NULL pointer\n");
+ else free(pt, M_DRM);
+ simple_lock(&drm_mem_lock);
+ drm_mem_stats[area].bytes_freed += size;
+ free_count = ++drm_mem_stats[area].free_count;
+ alloc_count = drm_mem_stats[area].succeed_count;
+ simple_unlock(&drm_mem_lock);
+ if (free_count > alloc_count) {
+ DRM_MEM_ERROR(area, "Excess frees: %d frees, %d allocs\n",
+ free_count, alloc_count);
+ }
+}
+
+unsigned long drm_alloc_pages(int order, int area)
+{
+ vm_offset_t address;
+ unsigned long bytes = PAGE_SIZE << order;
+ unsigned long addr;
+ unsigned int sz;
+
+ simple_lock(&drm_mem_lock);
+ if (drm_ram_used > +(DRM_RAM_PERCENT * drm_ram_available) / 100) {
+ simple_unlock(&drm_mem_lock);
+ return 0;
+ }
+ simple_unlock(&drm_mem_lock);
+
+ address = (vm_offset_t) contigmalloc(1<<order, M_DRM, M_WAITOK, 0, ~0, 1, 0);
+ if (!address) {
+ simple_lock(&drm_mem_lock);
+ ++drm_mem_stats[area].fail_count;
+ simple_unlock(&drm_mem_lock);
+ return 0;
+ }
+ simple_lock(&drm_mem_lock);
+ ++drm_mem_stats[area].succeed_count;
+ drm_mem_stats[area].bytes_allocated += bytes;
+ drm_ram_used += bytes;
+ simple_unlock(&drm_mem_lock);
+
+
+ /* Zero outside the lock */
+ memset((void *)address, 0, bytes);
+
+ /* Reserve */
+ for (addr = address, sz = bytes;
+ sz > 0;
+ addr += PAGE_SIZE, sz -= PAGE_SIZE) {
+ /* mem_map_reserve(MAP_NR(addr));*/
+ }
+
+ return address;
+}
+
+void drm_free_pages(unsigned long address, int order, int area)
+{
+ unsigned long bytes = PAGE_SIZE << order;
+ int alloc_count;
+ int free_count;
+ unsigned long addr;
+ unsigned int sz;
+
+ if (!address) {
+ DRM_MEM_ERROR(area, "Attempt to free address 0\n");
+ } else {
+ /* Unreserve */
+ for (addr = address, sz = bytes;
+ sz > 0;
+ addr += PAGE_SIZE, sz -= PAGE_SIZE) {
+ /* mem_map_unreserve(MAP_NR(addr));*/
+ }
+ contigfree((void *) address, bytes, M_DRM);
+ }
+
+ simple_lock(&drm_mem_lock);
+ free_count = ++drm_mem_stats[area].free_count;
+ alloc_count = drm_mem_stats[area].succeed_count;
+ drm_mem_stats[area].bytes_freed += bytes;
+ drm_ram_used -= bytes;
+ simple_unlock(&drm_mem_lock);
+ if (free_count > alloc_count) {
+ DRM_MEM_ERROR(area,
+ "Excess frees: %d frees, %d allocs\n",
+ free_count, alloc_count);
+ }
+}
+
+void *drm_ioremap(unsigned long offset, unsigned long size)
+{
+ void *pt;
+
+ if (!size) {
+ DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
+ "Mapping 0 bytes at 0x%08lx\n", offset);
+ return NULL;
+ }
+
+ if (!(pt = pmap_mapdev(offset, size))) {
+ simple_lock(&drm_mem_lock);
+ ++drm_mem_stats[DRM_MEM_MAPPINGS].fail_count;
+ simple_unlock(&drm_mem_lock);
+ return NULL;
+ }
+ simple_lock(&drm_mem_lock);
+ ++drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count;
+ drm_mem_stats[DRM_MEM_MAPPINGS].bytes_allocated += size;
+ simple_unlock(&drm_mem_lock);
+ return pt;
+}
+
+void drm_ioremapfree(void *pt, unsigned long size)
+{
+ int alloc_count;
+ int free_count;
+
+ if (!pt)
+ DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
+ "Attempt to free NULL pointer\n");
+ else
+ pmap_unmapdev((vm_offset_t) pt, size);
+
+ simple_lock(&drm_mem_lock);
+ drm_mem_stats[DRM_MEM_MAPPINGS].bytes_freed += size;
+ free_count = ++drm_mem_stats[DRM_MEM_MAPPINGS].free_count;
+ alloc_count = drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count;
+ simple_unlock(&drm_mem_lock);
+ if (free_count > alloc_count) {
+ DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
+ "Excess frees: %d frees, %d allocs\n",
+ free_count, alloc_count);
+ }
+}
+
+#ifdef DRM_AGP
+void *drm_alloc_agp(int pages, u_int32_t type)
+{
+ device_t dev = agp_find_device();
+ void *handle;
+
+ if (!dev)
+ return NULL;
+
+ if (!pages) {
+ DRM_MEM_ERROR(DRM_MEM_TOTALAGP, "Allocating 0 pages\n");
+ return NULL;
+ }
+
+ if ((handle = agp_alloc_memory(dev, type, pages << AGP_PAGE_SHIFT))) {
+ simple_lock(&drm_mem_lock);
+ ++drm_mem_stats[DRM_MEM_TOTALAGP].succeed_count;
+ drm_mem_stats[DRM_MEM_TOTALAGP].bytes_allocated
+ += pages << PAGE_SHIFT;
+ simple_unlock(&drm_mem_lock);
+ return handle;
+ }
+ simple_lock(&drm_mem_lock);
+ ++drm_mem_stats[DRM_MEM_TOTALAGP].fail_count;
+ simple_unlock(&drm_mem_lock);
+ return NULL;
+}
+
+int drm_free_agp(void *handle, int pages)
+{
+ device_t dev = agp_find_device();
+ int alloc_count;
+ int free_count;
+ int retval = EINVAL;
+
+ if (!dev)
+ return EINVAL;
+
+ if (!handle) {
+ DRM_MEM_ERROR(DRM_MEM_TOTALAGP,
+ "Attempt to free NULL AGP handle\n");
+ return retval;
+ }
+
+ agp_free_memory(dev, handle);
+ simple_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;
+ simple_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;
+}
+
+int drm_bind_agp(void *handle, unsigned int start)
+{
+ device_t dev = agp_find_device();
+ int retcode = EINVAL;
+ struct agp_memory_info info;
+
+ DRM_DEBUG("drm_bind_agp called\n");
+
+ if (!dev)
+ return EINVAL;
+
+ if (!handle) {
+ DRM_MEM_ERROR(DRM_MEM_BOUNDAGP,
+ "Attempt to bind NULL AGP handle\n");
+ return retcode;
+ }
+
+ if (!(retcode = agp_bind_memory(dev, handle,
+ start << AGP_PAGE_SHIFT))) {
+ simple_lock(&drm_mem_lock);
+ ++drm_mem_stats[DRM_MEM_BOUNDAGP].succeed_count;
+ agp_memory_info(dev, handle, &info);
+ drm_mem_stats[DRM_MEM_BOUNDAGP].bytes_allocated
+ += info.ami_size;
+ simple_unlock(&drm_mem_lock);
+ DRM_DEBUG("drm_agp.bind_memory: retcode %d\n", retcode);
+ return retcode;
+ }
+ simple_lock(&drm_mem_lock);
+ ++drm_mem_stats[DRM_MEM_BOUNDAGP].fail_count;
+ simple_unlock(&drm_mem_lock);
+ return retcode;
+}
+
+int drm_unbind_agp(void *handle)
+{
+ device_t dev = agp_find_device();
+ int alloc_count;
+ int free_count;
+ int retcode = EINVAL;
+ struct agp_memory_info info;
+
+ if (!dev)
+ return EINVAL;
+
+ if (!handle) {
+ DRM_MEM_ERROR(DRM_MEM_BOUNDAGP,
+ "Attempt to unbind NULL AGP handle\n");
+ return retcode;
+ }
+
+
+ agp_memory_info(dev, handle, &info);
+ if ((retcode = agp_unbind_memory(dev, handle)))
+ return retcode;
+ simple_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 += info.ami_size;
+ simple_unlock(&drm_mem_lock);
+ if (free_count > alloc_count) {
+ DRM_MEM_ERROR(DRM_MEM_BOUNDAGP,
+ "Excess frees: %d frees, %d allocs\n",
+ free_count, alloc_count);
+ }
+ return retcode;
+}
+#endif
diff --git a/bsd/drm/proc.c b/bsd/drm/proc.c
new file mode 100644
index 00000000..12168aa3
--- /dev/null
+++ b/bsd/drm/proc.c
@@ -0,0 +1,568 @@
+/* proc.c -- /proc support for DRM -*- c -*-
+ * Created: Mon Jan 11 09:48:47 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 11:31:48 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/proc.c,v 1.4 1999/08/20 15:36:46 faith Exp $
+ * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/proc.c,v 1.1 1999/09/25 14:38:02 dawes Exp $
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+static struct proc_dir_entry *drm_root = NULL;
+static struct proc_dir_entry *drm_dev_root = NULL;
+static char drm_slot_name[64];
+
+static int drm_name_info(char *buf, char **start, off_t offset,
+ int len, int *eof, void *data);
+static int drm_vm_info(char *buf, char **start, off_t offset,
+ int len, int *eof, void *data);
+static int drm_clients_info(char *buf, char **start, off_t offset,
+ int len, int *eof, void *data);
+static int drm_queues_info(char *buf, char **start, off_t offset,
+ int len, int *eof, void *data);
+static int drm_bufs_info(char *buf, char **start, off_t offset,
+ int len, int *eof, void *data);
+#if DRM_DEBUG_CODE
+static int drm_vma_info(char *buf, char **start, off_t offset,
+ int len, int *eof, void *data);
+#endif
+#if DRM_DMA_HISTOGRAM
+static int drm_histo_info(char *buf, char **start, off_t offset,
+ int len, int *eof, void *data);
+#endif
+
+struct drm_proc_list {
+ const char *name;
+ int (*f)(char *, char **, off_t, int, int *, void *);
+} drm_proc_list[] = {
+ { "name", drm_name_info },
+ { "mem", drm_mem_info },
+ { "vm", drm_vm_info },
+ { "clients", drm_clients_info },
+ { "queues", drm_queues_info },
+ { "bufs", drm_bufs_info },
+#if DRM_DEBUG_CODE
+ { "vma", drm_vma_info },
+#endif
+#if DRM_DMA_HISTOGRAM
+ { "histo", drm_histo_info },
+#endif
+};
+#define DRM_PROC_ENTRIES (sizeof(drm_proc_list)/sizeof(drm_proc_list[0]))
+
+int drm_proc_init(drm_device_t *dev)
+{
+ struct proc_dir_entry *ent;
+ int i, j;
+
+ drm_root = create_proc_entry("graphics", S_IFDIR, NULL);
+ if (!drm_root) {
+ DRM_ERROR("Cannot create /proc/graphics\n");
+ return -1;
+ }
+
+ /* Instead of doing this search, we should
+ add some global support for /proc/graphics. */
+ for (i = 0; i < 8; i++) {
+ sprintf(drm_slot_name, "graphics/%d", i);
+ drm_dev_root = create_proc_entry(drm_slot_name, S_IFDIR, NULL);
+ if (!drm_dev_root) {
+ DRM_ERROR("Cannot create /proc/%s\n", drm_slot_name);
+ remove_proc_entry("graphics", NULL);
+ }
+ if (drm_dev_root->nlink == 2) break;
+ drm_dev_root = NULL;
+ }
+ if (!drm_dev_root) {
+ DRM_ERROR("Cannot find slot in /proc/graphics\n");
+ return -1;
+ }
+
+ for (i = 0; i < DRM_PROC_ENTRIES; i++) {
+ ent = create_proc_entry(drm_proc_list[i].name,
+ S_IFREG|S_IRUGO, drm_dev_root);
+ if (!ent) {
+ DRM_ERROR("Cannot create /proc/%s/%s\n",
+ drm_slot_name, drm_proc_list[i].name);
+ for (j = 0; j < i; j++)
+ remove_proc_entry(drm_proc_list[i].name,
+ drm_dev_root);
+ remove_proc_entry(drm_slot_name, NULL);
+ remove_proc_entry("graphics", NULL);
+ return -1;
+ }
+ ent->read_proc = drm_proc_list[i].f;
+ ent->data = dev;
+ }
+
+ return 0;
+}
+
+
+int drm_proc_cleanup(void)
+{
+ int i;
+
+ if (drm_root) {
+ if (drm_dev_root) {
+ for (i = 0; i < DRM_PROC_ENTRIES; i++) {
+ remove_proc_entry(drm_proc_list[i].name,
+ drm_dev_root);
+ }
+ remove_proc_entry(drm_slot_name, NULL);
+ }
+ remove_proc_entry("graphics", NULL);
+ remove_proc_entry(DRM_NAME, NULL);
+ }
+ drm_root = drm_dev_root = NULL;
+ return 0;
+}
+
+static int drm_name_info(char *buf, char **start, off_t offset, int len,
+ int *eof, void *data)
+{
+ drm_device_t *dev = (drm_device_t *)data;
+
+ if (offset > 0) return 0; /* no partial requests */
+ len = 0;
+ *eof = 1;
+
+ if (dev->unique) {
+ DRM_PROC_PRINT("%s 0x%x %s\n",
+ dev->name, dev->device, dev->unique);
+ } else {
+ DRM_PROC_PRINT("%s 0x%x\n", dev->name, dev->device);
+ }
+ return len;
+}
+
+static int _drm_vm_info(char *buf, char **start, off_t offset, int len,
+ int *eof, void *data)
+{
+ drm_device_t *dev = (drm_device_t *)data;
+ drm_map_t *map;
+ const char *types[] = { "FB", "REG", "SHM" };
+ const char *type;
+ int i;
+
+ if (offset > 0) return 0; /* no partial requests */
+ len = 0;
+ *eof = 1;
+ DRM_PROC_PRINT("slot offset size type flags "
+ "address mtrr\n\n");
+ for (i = 0; i < dev->map_count; i++) {
+ map = dev->maplist[i];
+ if (map->type < 0 || map->type > 2) type = "??";
+ else type = types[map->type];
+ DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s 0x%02x 0x%08lx ",
+ i,
+ map->offset,
+ map->size,
+ type,
+ map->flags,
+ (unsigned long)map->handle);
+ if (map->mtrr < 0) {
+ DRM_PROC_PRINT("none\n");
+ } else {
+ DRM_PROC_PRINT("%4d\n", map->mtrr);
+ }
+ }
+
+ return len;
+}
+
+static int drm_vm_info(char *buf, char **start, off_t offset, int len,
+ int *eof, void *data)
+{
+ drm_device_t *dev = (drm_device_t *)data;
+ int ret;
+
+ down(&dev->struct_sem);
+ ret = _drm_vm_info(buf, start, offset, len, eof, data);
+ up(&dev->struct_sem);
+ return ret;
+}
+
+
+static int _drm_queues_info(char *buf, char **start, off_t offset, int len,
+ int *eof, void *data)
+{
+ drm_device_t *dev = (drm_device_t *)data;
+ int i;
+ drm_queue_t *q;
+
+ if (offset > 0) return 0; /* no partial requests */
+ len = 0;
+ *eof = 1;
+ DRM_PROC_PRINT(" ctx/flags use fin"
+ " blk/rw/rwf wait flushed queued"
+ " locks\n\n");
+ for (i = 0; i < dev->queue_count; i++) {
+ q = dev->queuelist[i];
+ atomic_inc(&q->use_count);
+ DRM_PROC_PRINT_RET(atomic_dec(&q->use_count),
+ "%5d/0x%03x %5d %5d"
+ " %5d/%c%c/%c%c%c %5d %10d %10d %10d\n",
+ i,
+ q->flags,
+ atomic_read(&q->use_count),
+ atomic_read(&q->finalization),
+ atomic_read(&q->block_count),
+ atomic_read(&q->block_read) ? 'r' : '-',
+ atomic_read(&q->block_write) ? 'w' : '-',
+ waitqueue_active(&q->read_queue) ? 'r':'-',
+ waitqueue_active(&q->write_queue) ? 'w':'-',
+ waitqueue_active(&q->flush_queue) ? 'f':'-',
+ DRM_BUFCOUNT(&q->waitlist),
+ atomic_read(&q->total_flushed),
+ atomic_read(&q->total_queued),
+ atomic_read(&q->total_locks));
+ atomic_dec(&q->use_count);
+ }
+
+ return len;
+}
+
+static int drm_queues_info(char *buf, char **start, off_t offset, int len,
+ int *eof, void *data)
+{
+ drm_device_t *dev = (drm_device_t *)data;
+ int ret;
+
+ down(&dev->struct_sem);
+ ret = _drm_queues_info(buf, start, offset, len, eof, data);
+ up(&dev->struct_sem);
+ return ret;
+}
+
+/* drm_bufs_info is called whenever a process reads
+ /dev/drm/<dev>/bufs. */
+
+static int _drm_bufs_info(char *buf, char **start, off_t offset, int len,
+ int *eof, void *data)
+{
+ drm_device_t *dev = (drm_device_t *)data;
+ drm_device_dma_t *dma = dev->dma;
+ int i;
+
+ if (!dma) return 0;
+ if (offset > 0) return 0; /* no partial requests */
+ len = 0;
+ *eof = 1;
+ DRM_PROC_PRINT(" o size count free segs pages kB\n\n");
+ for (i = 0; i <= DRM_MAX_ORDER; i++) {
+ if (dma->bufs[i].buf_count)
+ DRM_PROC_PRINT("%2d %8d %5d %5d %5d %5d %5ld\n",
+ i,
+ dma->bufs[i].buf_size,
+ dma->bufs[i].buf_count,
+ atomic_read(&dma->bufs[i]
+ .freelist.count),
+ dma->bufs[i].seg_count,
+ dma->bufs[i].seg_count
+ *(1 << dma->bufs[i].page_order),
+ (dma->bufs[i].seg_count
+ * (1 << dma->bufs[i].page_order))
+ * PAGE_SIZE / 1024);
+ }
+ DRM_PROC_PRINT("\n");
+ for (i = 0; i < dma->buf_count; i++) {
+ if (i && !(i%32)) DRM_PROC_PRINT("\n");
+ DRM_PROC_PRINT(" %d", dma->buflist[i]->list);
+ }
+ DRM_PROC_PRINT("\n");
+
+ return len;
+}
+
+static int drm_bufs_info(char *buf, char **start, off_t offset, int len,
+ int *eof, void *data)
+{
+ drm_device_t *dev = (drm_device_t *)data;
+ int ret;
+
+ down(&dev->struct_sem);
+ ret = _drm_bufs_info(buf, start, offset, len, eof, data);
+ up(&dev->struct_sem);
+ return ret;
+}
+
+
+static int _drm_clients_info(char *buf, char **start, off_t offset, int len,
+ int *eof, void *data)
+{
+ drm_device_t *dev = (drm_device_t *)data;
+ drm_file_t *priv;
+
+ if (offset > 0) return 0; /* no partial requests */
+ len = 0;
+ *eof = 1;
+ DRM_PROC_PRINT("a dev pid uid magic ioctls\n\n");
+ for (priv = dev->file_first; priv; priv = priv->next) {
+ DRM_PROC_PRINT("%c %3d %5d %5d %10u %10lu\n",
+ priv->authenticated ? 'y' : 'n',
+ priv->minor,
+ priv->pid,
+ priv->uid,
+ priv->magic,
+ priv->ioctl_count);
+ }
+
+ return len;
+}
+
+static int drm_clients_info(char *buf, char **start, off_t offset, int len,
+ int *eof, void *data)
+{
+ drm_device_t *dev = (drm_device_t *)data;
+ int ret;
+
+ down(&dev->struct_sem);
+ ret = _drm_clients_info(buf, start, offset, len, eof, data);
+ up(&dev->struct_sem);
+ return ret;
+}
+
+#if DRM_DEBUG_CODE
+
+static int _drm_vma_info(char *buf, char **start, off_t offset, int len,
+ int *eof, void *data)
+{
+ drm_device_t *dev = (drm_device_t *)data;
+ drm_vma_entry_t *pt;
+ pgd_t *pgd;
+ pmd_t *pmd;
+ pte_t *pte;
+ unsigned long i;
+ struct vm_area_struct *vma;
+ unsigned long address;
+#if defined(__i386__)
+ unsigned int pgprot;
+#endif
+
+ if (offset > 0) return 0; /* no partial requests */
+ len = 0;
+ *eof = 1;
+ DRM_PROC_PRINT("vma use count: %d, high_memory = %p, 0x%08lx\n",
+ atomic_read(&dev->vma_count),
+ high_memory, virt_to_phys(high_memory));
+ for (pt = dev->vmalist; pt; pt = pt->next) {
+ if (!(vma = pt->vma)) continue;
+ DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx",
+ pt->pid,
+ vma->vm_start,
+ vma->vm_end,
+ vma->vm_flags & VM_READ ? 'r' : '-',
+ vma->vm_flags & VM_WRITE ? 'w' : '-',
+ vma->vm_flags & VM_EXEC ? 'x' : '-',
+ vma->vm_flags & VM_MAYSHARE ? 's' : 'p',
+ vma->vm_flags & VM_LOCKED ? 'l' : '-',
+ vma->vm_flags & VM_IO ? 'i' : '-',
+ vma->vm_offset );
+#if defined(__i386__)
+ pgprot = pgprot_val(vma->vm_page_prot);
+ DRM_PROC_PRINT(" %c%c%c%c%c%c%c%c%c",
+ pgprot & _PAGE_PRESENT ? 'p' : '-',
+ pgprot & _PAGE_RW ? 'w' : 'r',
+ pgprot & _PAGE_USER ? 'u' : 's',
+ pgprot & _PAGE_PWT ? 't' : 'b',
+ pgprot & _PAGE_PCD ? 'u' : 'c',
+ pgprot & _PAGE_ACCESSED ? 'a' : '-',
+ pgprot & _PAGE_DIRTY ? 'd' : '-',
+ pgprot & _PAGE_4M ? 'm' : 'k',
+ pgprot & _PAGE_GLOBAL ? 'g' : 'l' );
+#endif
+ DRM_PROC_PRINT("\n");
+ for (i = vma->vm_start; i < vma->vm_end; i += PAGE_SIZE) {
+ pgd = pgd_offset(vma->vm_mm, i);
+ pmd = pmd_offset(pgd, i);
+ pte = pte_offset(pmd, i);
+ if (pte_present(*pte)) {
+ address = __pa(pte_page(*pte))
+ + (i & (PAGE_SIZE-1));
+ DRM_PROC_PRINT(" 0x%08lx -> 0x%08lx"
+ " %c%c%c%c%c\n",
+ i,
+ address,
+ pte_read(*pte) ? 'r' : '-',
+ pte_write(*pte) ? 'w' : '-',
+ pte_exec(*pte) ? 'x' : '-',
+ pte_dirty(*pte) ? 'd' : '-',
+ pte_young(*pte) ? 'a' : '-' );
+ } else {
+ DRM_PROC_PRINT(" 0x%08lx\n", i);
+ }
+ }
+ }
+
+ return len;
+}
+
+static int drm_vma_info(char *buf, char **start, off_t offset, int len,
+ int *eof, void *data)
+{
+ drm_device_t *dev = (drm_device_t *)data;
+ int ret;
+
+ down(&dev->struct_sem);
+ ret = _drm_vma_info(buf, start, offset, len, eof, data);
+ up(&dev->struct_sem);
+ return ret;
+}
+#endif
+
+
+#if DRM_DMA_HISTOGRAM
+static int _drm_histo_info(char *buf, char **start, off_t offset, int len,
+ int *eof, void *data)
+{
+ drm_device_t *dev = (drm_device_t *)data;
+ drm_device_dma_t *dma = dev->dma;
+ int i;
+ unsigned long slot_value = DRM_DMA_HISTOGRAM_INITIAL;
+ unsigned long prev_value = 0;
+ drm_buf_t *buffer;
+
+ if (offset > 0) return 0; /* no partial requests */
+ len = 0;
+ *eof = 1;
+
+ DRM_PROC_PRINT("general statistics:\n");
+ DRM_PROC_PRINT("total %10u\n", atomic_read(&dev->histo.total));
+ DRM_PROC_PRINT("open %10u\n", atomic_read(&dev->total_open));
+ DRM_PROC_PRINT("close %10u\n", atomic_read(&dev->total_close));
+ DRM_PROC_PRINT("ioctl %10u\n", atomic_read(&dev->total_ioctl));
+ DRM_PROC_PRINT("irq %10u\n", atomic_read(&dev->total_irq));
+ DRM_PROC_PRINT("ctx %10u\n", atomic_read(&dev->total_ctx));
+
+ DRM_PROC_PRINT("\nlock statistics:\n");
+ DRM_PROC_PRINT("locks %10u\n", atomic_read(&dev->total_locks));
+ DRM_PROC_PRINT("unlocks %10u\n", atomic_read(&dev->total_unlocks));
+ DRM_PROC_PRINT("contends %10u\n", atomic_read(&dev->total_contends));
+ DRM_PROC_PRINT("sleeps %10u\n", atomic_read(&dev->total_sleeps));
+
+
+ if (dma) {
+ DRM_PROC_PRINT("\ndma statistics:\n");
+ DRM_PROC_PRINT("prio %10u\n",
+ atomic_read(&dma->total_prio));
+ DRM_PROC_PRINT("bytes %10u\n",
+ atomic_read(&dma->total_bytes));
+ DRM_PROC_PRINT("dmas %10u\n",
+ atomic_read(&dma->total_dmas));
+ DRM_PROC_PRINT("missed:\n");
+ DRM_PROC_PRINT(" dma %10u\n",
+ atomic_read(&dma->total_missed_dma));
+ DRM_PROC_PRINT(" lock %10u\n",
+ atomic_read(&dma->total_missed_lock));
+ DRM_PROC_PRINT(" free %10u\n",
+ atomic_read(&dma->total_missed_free));
+ DRM_PROC_PRINT(" sched %10u\n",
+ atomic_read(&dma->total_missed_sched));
+ DRM_PROC_PRINT("tried %10u\n",
+ atomic_read(&dma->total_tried));
+ DRM_PROC_PRINT("hit %10u\n",
+ atomic_read(&dma->total_hit));
+ DRM_PROC_PRINT("lost %10u\n",
+ atomic_read(&dma->total_lost));
+
+ buffer = dma->next_buffer;
+ if (buffer) {
+ DRM_PROC_PRINT("next_buffer %7d\n", buffer->idx);
+ } else {
+ DRM_PROC_PRINT("next_buffer none\n");
+ }
+ buffer = dma->this_buffer;
+ if (buffer) {
+ DRM_PROC_PRINT("this_buffer %7d\n", buffer->idx);
+ } else {
+ DRM_PROC_PRINT("this_buffer none\n");
+ }
+ }
+
+
+ DRM_PROC_PRINT("\nvalues:\n");
+ if (dev->lock.hw_lock) {
+ DRM_PROC_PRINT("lock 0x%08x\n",
+ dev->lock.hw_lock->lock);
+ } else {
+ DRM_PROC_PRINT("lock none\n");
+ }
+ DRM_PROC_PRINT("context_flag 0x%08x\n", dev->context_flag);
+ DRM_PROC_PRINT("interrupt_flag 0x%08x\n", dev->interrupt_flag);
+ DRM_PROC_PRINT("dma_flag 0x%08x\n", dev->dma_flag);
+
+ DRM_PROC_PRINT("queue_count %10d\n", dev->queue_count);
+ DRM_PROC_PRINT("last_context %10d\n", dev->last_context);
+ DRM_PROC_PRINT("last_switch %10lu\n", dev->last_switch);
+ DRM_PROC_PRINT("last_checked %10d\n", dev->last_checked);
+
+
+ DRM_PROC_PRINT("\n q2d d2c c2f"
+ " q2c q2f dma sch"
+ " ctx lacq lhld\n\n");
+ for (i = 0; i < DRM_DMA_HISTOGRAM_SLOTS; i++) {
+ DRM_PROC_PRINT("%s %10lu %10u %10u %10u %10u %10u"
+ " %10u %10u %10u %10u %10u\n",
+ i == DRM_DMA_HISTOGRAM_SLOTS - 1 ? ">=" : "< ",
+ i == DRM_DMA_HISTOGRAM_SLOTS - 1
+ ? prev_value : slot_value ,
+
+ atomic_read(&dev->histo
+ .queued_to_dispatched[i]),
+ atomic_read(&dev->histo
+ .dispatched_to_completed[i]),
+ atomic_read(&dev->histo
+ .completed_to_freed[i]),
+
+ atomic_read(&dev->histo
+ .queued_to_completed[i]),
+ atomic_read(&dev->histo
+ .queued_to_freed[i]),
+ atomic_read(&dev->histo.dma[i]),
+ atomic_read(&dev->histo.schedule[i]),
+ atomic_read(&dev->histo.ctx[i]),
+ atomic_read(&dev->histo.lacq[i]),
+ atomic_read(&dev->histo.lhld[i]));
+ prev_value = slot_value;
+ slot_value = DRM_DMA_HISTOGRAM_NEXT(slot_value);
+ }
+ return len;
+}
+
+static int drm_histo_info(char *buf, char **start, off_t offset, int len,
+ int *eof, void *data)
+{
+ drm_device_t *dev = (drm_device_t *)data;
+ int ret;
+
+ down(&dev->struct_sem);
+ ret = _drm_histo_info(buf, start, offset, len, eof, data);
+ up(&dev->struct_sem);
+ return ret;
+}
+#endif
diff --git a/bsd/drm/sysctl.c b/bsd/drm/sysctl.c
new file mode 100644
index 00000000..7c736abf
--- /dev/null
+++ b/bsd/drm/sysctl.c
@@ -0,0 +1,554 @@
+/* proc.c -- /proc support for DRM -*- c -*-
+ * Created: Mon Jan 11 09:48:47 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 11:31:48 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * $PI$
+ * $XFree86$
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+#include <sys/sysctl.h>
+
+SYSCTL_NODE(_hw, OID_AUTO, dri, CTLFLAG_RW, 0, "DRI Graphics");
+
+static int drm_name_info SYSCTL_HANDLER_ARGS;
+static int drm_vm_info SYSCTL_HANDLER_ARGS;
+static int drm_clients_info SYSCTL_HANDLER_ARGS;
+static int drm_queues_info SYSCTL_HANDLER_ARGS;
+static int drm_bufs_info SYSCTL_HANDLER_ARGS;
+#if DRM_DEBUG_CODExx
+static int drm_vma_info SYSCTL_HANDLER_ARGS;
+#endif
+#if DRM_DMA_HISTOGRAM
+static int drm_histo_info SYSCTL_HANDLER_ARGS;
+#endif
+
+struct drm_sysctl_list {
+ const char *name;
+ int (*f) SYSCTL_HANDLER_ARGS;
+} drm_sysctl_list[] = {
+ { "name", drm_name_info },
+ { "mem", drm_mem_info },
+ { "vm", drm_vm_info },
+ { "clients", drm_clients_info },
+ { "queues", drm_queues_info },
+ { "bufs", drm_bufs_info },
+#if DRM_DEBUG_CODExx
+ { "vma", drm_vma_info },
+#endif
+#if DRM_DMA_HISTOGRAM
+ { "histo", drm_histo_info },
+#endif
+};
+#define DRM_SYSCTL_ENTRIES (sizeof(drm_sysctl_list)/sizeof(drm_sysctl_list[0]))
+
+struct drm_sysctl_info {
+ struct sysctl_oid oids[DRM_SYSCTL_ENTRIES + 1];
+ struct sysctl_oid_list list;
+ char name[2];
+};
+
+int drm_sysctl_init(drm_device_t *dev)
+{
+ struct drm_sysctl_info *info;
+ struct sysctl_oid *oid;
+ struct sysctl_oid *top;
+ int i;
+
+ /* Find the next free slot under hw.graphics */
+ i = 0;
+ SLIST_FOREACH(oid, &sysctl__hw_dri_children, oid_link) {
+ if (i <= oid->oid_arg2)
+ i = oid->oid_arg2 + 1;
+ }
+
+ info = drm_alloc(sizeof *info, DRM_MEM_DRIVER);
+ dev->sysctl = info;
+
+ /* Construct the node under hw.graphics */
+ info->name[0] = '0' + i;
+ info->name[1] = 0;
+ oid = &info->oids[DRM_SYSCTL_ENTRIES];
+ bzero(oid, sizeof(*oid));
+ oid->oid_parent = &sysctl__hw_dri_children;
+ oid->oid_number = OID_AUTO;
+ oid->oid_kind = CTLTYPE_NODE | CTLFLAG_RW;
+ oid->oid_arg1 = &info->list;
+ oid->oid_arg2 = i;
+ oid->oid_name = info->name;
+ oid->oid_handler = 0;
+ oid->oid_fmt = "N";
+ SLIST_INIT(&info->list);
+ sysctl_register_oid(oid);
+ top = oid;
+
+ for (i = 0; i < DRM_SYSCTL_ENTRIES; i++) {
+ oid = &info->oids[i];
+ bzero(oid, sizeof(*oid));
+ oid->oid_parent = top->oid_arg1;
+ oid->oid_number = OID_AUTO;
+ oid->oid_kind = CTLTYPE_INT | CTLFLAG_RD;
+ oid->oid_arg1 = dev;
+ oid->oid_arg2 = 0;
+ oid->oid_name = drm_sysctl_list[i].name;
+ oid->oid_handler = drm_sysctl_list[i].f;
+ oid->oid_fmt = "A";
+ sysctl_register_oid(oid);
+ }
+
+ return 0;
+}
+
+int drm_sysctl_cleanup(drm_device_t *dev)
+{
+ int i;
+
+ DRM_DEBUG("dev->sysctl=%p\n", dev->sysctl);
+ for (i = 0; i < DRM_SYSCTL_ENTRIES + 1; i++)
+ sysctl_unregister_oid(&dev->sysctl->oids[i]);
+
+ drm_free(dev->sysctl, sizeof *dev->sysctl, DRM_MEM_DRIVER);
+ dev->sysctl = NULL;
+
+ return 0;
+}
+
+static int drm_name_info SYSCTL_HANDLER_ARGS
+{
+ drm_device_t *dev = arg1;
+ char buf[128];
+ int error;
+
+ if (dev->unique) {
+ DRM_SYSCTL_PRINT("%s 0x%x %s\n",
+ dev->name, dev2udev(dev->devnode), dev->unique);
+ } else {
+ DRM_SYSCTL_PRINT("%s 0x%x\n", dev->name, dev2udev(dev->devnode));
+ }
+
+ SYSCTL_OUT(req, "", 1);
+
+ return 0;
+}
+
+static int _drm_vm_info SYSCTL_HANDLER_ARGS
+{
+ drm_device_t *dev = arg1;
+ drm_map_t *map;
+ const char *types[] = { "FB", "REG", "SHM" };
+ const char *type;
+ int i;
+ char buf[128];
+ int error;
+
+ DRM_SYSCTL_PRINT("slot offset size type flags "
+ "address mtrr\n\n");
+ error = SYSCTL_OUT(req, buf, strlen(buf));
+ if (error) return error;
+
+ for (i = 0; i < dev->map_count; i++) {
+ map = dev->maplist[i];
+ if (map->type < 0 || map->type > 2) type = "??";
+ else type = types[map->type];
+ DRM_SYSCTL_PRINT("%4d 0x%08lx 0x%08lx %4.4s 0x%02x 0x%08lx ",
+ i,
+ map->offset,
+ map->size,
+ type,
+ map->flags,
+ (unsigned long)map->handle);
+ if (map->mtrr < 0) {
+ DRM_SYSCTL_PRINT("none\n");
+ } else {
+ DRM_SYSCTL_PRINT("%4d\n", map->mtrr);
+ }
+ }
+ SYSCTL_OUT(req, "", 1);
+
+ return 0;
+}
+
+static int drm_vm_info SYSCTL_HANDLER_ARGS
+{
+ drm_device_t *dev = arg1;
+ int ret;
+
+ lockmgr(&dev->dev_lock, LK_EXCLUSIVE, 0, curproc);
+ ret = _drm_vm_info(oidp, arg1, arg2, req);
+ lockmgr(&dev->dev_lock, LK_RELEASE, 0, curproc);
+
+ return ret;
+}
+
+
+static int _drm_queues_info SYSCTL_HANDLER_ARGS
+{
+ drm_device_t *dev = arg1;
+ int i;
+ drm_queue_t *q;
+ char buf[128];
+ int error;
+
+ DRM_SYSCTL_PRINT(" ctx/flags use fin"
+ " blk/rw/rwf wait flushed queued"
+ " locks\n\n");
+ for (i = 0; i < dev->queue_count; i++) {
+ q = dev->queuelist[i];
+ atomic_inc(&q->use_count);
+ DRM_SYSCTL_PRINT_RET(atomic_dec(&q->use_count),
+ "%5d/0x%03x %5d %5d"
+ " %5d/%c%c/%c%c%c %5d %10d %10d %10d\n",
+ i,
+ q->flags,
+ atomic_read(&q->use_count),
+ atomic_read(&q->finalization),
+ atomic_read(&q->block_count),
+ atomic_read(&q->block_read) ? 'r' : '-',
+ atomic_read(&q->block_write) ? 'w' : '-',
+ q->read_queue ? 'r':'-',
+ q->write_queue ? 'w':'-',
+ q->flush_queue ? 'f':'-',
+ DRM_BUFCOUNT(&q->waitlist),
+ atomic_read(&q->total_flushed),
+ atomic_read(&q->total_queued),
+ atomic_read(&q->total_locks));
+ atomic_dec(&q->use_count);
+ }
+
+ SYSCTL_OUT(req, "", 1);
+ return 0;
+}
+
+static int drm_queues_info SYSCTL_HANDLER_ARGS
+{
+ drm_device_t *dev = arg1;
+ int ret;
+
+ lockmgr(&dev->dev_lock, LK_EXCLUSIVE, 0, curproc);
+ ret = _drm_queues_info(oidp, arg1, arg2, req);
+ lockmgr(&dev->dev_lock, LK_RELEASE, 0, curproc);
+ return ret;
+}
+
+/* drm_bufs_info is called whenever a process reads
+ hw.dri.0.bufs. */
+
+static int _drm_bufs_info SYSCTL_HANDLER_ARGS
+{
+ drm_device_t *dev = arg1;
+ drm_device_dma_t *dma = dev->dma;
+ int i;
+ char buf[128];
+ int error;
+
+ if (!dma) return 0;
+ DRM_SYSCTL_PRINT(" o size count free segs pages kB\n\n");
+ for (i = 0; i <= DRM_MAX_ORDER; i++) {
+ if (dma->bufs[i].buf_count)
+ DRM_SYSCTL_PRINT("%2d %8d %5d %5d %5d %5d %5d\n",
+ i,
+ dma->bufs[i].buf_size,
+ dma->bufs[i].buf_count,
+ atomic_read(&dma->bufs[i]
+ .freelist.count),
+ dma->bufs[i].seg_count,
+ dma->bufs[i].seg_count
+ *(1 << dma->bufs[i].page_order),
+ (dma->bufs[i].seg_count
+ * (1 << dma->bufs[i].page_order))
+ * PAGE_SIZE / 1024);
+ }
+ DRM_SYSCTL_PRINT("\n");
+ for (i = 0; i < dma->buf_count; i++) {
+ if (i && !(i%32)) DRM_SYSCTL_PRINT("\n");
+ DRM_SYSCTL_PRINT(" %d", dma->buflist[i]->list);
+ }
+ DRM_SYSCTL_PRINT("\n");
+
+ SYSCTL_OUT(req, "", 1);
+ return 0;
+}
+
+static int drm_bufs_info SYSCTL_HANDLER_ARGS
+{
+ drm_device_t *dev = arg1;
+ int ret;
+
+ lockmgr(&dev->dev_lock, LK_EXCLUSIVE, 0, curproc);
+ ret = _drm_bufs_info(oidp, arg1, arg2, req);
+ lockmgr(&dev->dev_lock, LK_RELEASE, 0, curproc);
+ return ret;
+}
+
+
+static int _drm_clients_info SYSCTL_HANDLER_ARGS
+{
+ drm_device_t *dev = arg1;
+ drm_file_t *priv;
+ char buf[128];
+ int error;
+
+ DRM_SYSCTL_PRINT("a dev pid uid magic ioctls\n\n");
+ TAILQ_FOREACH(priv, &dev->files, link) {
+ DRM_SYSCTL_PRINT("%c %3d %5d %5d %10u %10lu\n",
+ priv->authenticated ? 'y' : 'n',
+ priv->minor,
+ priv->pid,
+ priv->uid,
+ priv->magic,
+ priv->ioctl_count);
+ }
+
+ SYSCTL_OUT(req, "", 1);
+ return 0;
+}
+
+static int drm_clients_info SYSCTL_HANDLER_ARGS
+{
+ drm_device_t *dev = arg1;
+ int ret;
+
+ lockmgr(&dev->dev_lock, LK_EXCLUSIVE, 0, curproc);
+ ret = _drm_clients_info(oidp, arg1, arg2, req);
+ lockmgr(&dev->dev_lock, LK_RELEASE, 0, curproc);
+ return ret;
+}
+
+#if DRM_DEBUG_CODExx
+
+static int _drm_vma_info SYSCTL_HANDLER_ARGS
+{
+ drm_device_t *dev = arg1;
+ drm_vma_entry_t *pt;
+ pgd_t *pgd;
+ pmd_t *pmd;
+ pte_t *pte;
+ unsigned long i;
+ struct vm_area_struct *vma;
+ unsigned long address;
+#if defined(__i386__)
+ unsigned int pgprot;
+#endif
+ char buf[128];
+ int error;
+
+ DRM_SYSCTL_PRINT("vma use count: %d, high_memory = %p, 0x%08lx\n",
+ atomic_read(&dev->vma_count),
+ high_memory, virt_to_phys(high_memory));
+ for (pt = dev->vmalist; pt; pt = pt->next) {
+ if (!(vma = pt->vma)) continue;
+ DRM_SYSCTL_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx",
+ pt->pid,
+ vma->vm_start,
+ vma->vm_end,
+ vma->vm_flags & VM_READ ? 'r' : '-',
+ vma->vm_flags & VM_WRITE ? 'w' : '-',
+ vma->vm_flags & VM_EXEC ? 'x' : '-',
+ vma->vm_flags & VM_MAYSHARE ? 's' : 'p',
+ vma->vm_flags & VM_LOCKED ? 'l' : '-',
+ vma->vm_flags & VM_IO ? 'i' : '-',
+ vma->vm_offset );
+#if defined(__i386__)
+ pgprot = pgprot_val(vma->vm_page_prot);
+ DRM_SYSCTL_PRINT(" %c%c%c%c%c%c%c%c%c",
+ pgprot & _PAGE_PRESENT ? 'p' : '-',
+ pgprot & _PAGE_RW ? 'w' : 'r',
+ pgprot & _PAGE_USER ? 'u' : 's',
+ pgprot & _PAGE_PWT ? 't' : 'b',
+ pgprot & _PAGE_PCD ? 'u' : 'c',
+ pgprot & _PAGE_ACCESSED ? 'a' : '-',
+ pgprot & _PAGE_DIRTY ? 'd' : '-',
+ pgprot & _PAGE_4M ? 'm' : 'k',
+ pgprot & _PAGE_GLOBAL ? 'g' : 'l' );
+#endif
+ DRM_SYSCTL_PRINT("\n");
+ for (i = vma->vm_start; i < vma->vm_end; i += PAGE_SIZE) {
+ pgd = pgd_offset(vma->vm_mm, i);
+ pmd = pmd_offset(pgd, i);
+ pte = pte_offset(pmd, i);
+ if (pte_present(*pte)) {
+ address = __pa(pte_page(*pte))
+ + (i & (PAGE_SIZE-1));
+ DRM_SYSCTL_PRINT(" 0x%08lx -> 0x%08lx"
+ " %c%c%c%c%c\n",
+ i,
+ address,
+ pte_read(*pte) ? 'r' : '-',
+ pte_write(*pte) ? 'w' : '-',
+ pte_exec(*pte) ? 'x' : '-',
+ pte_dirty(*pte) ? 'd' : '-',
+ pte_young(*pte) ? 'a' : '-' );
+ } else {
+ DRM_SYSCTL_PRINT(" 0x%08lx\n", i);
+ }
+ }
+ }
+
+ SYSCTL_OUT(req, "", 1);
+ return 0;
+}
+
+static int drm_vma_info SYSCTL_HANDLER_ARGS
+{
+ drm_device_t *dev = arg1;
+ int ret;
+
+ lockmgr(&dev->dev_lock, LK_EXCLUSIVE, 0, curproc);
+ ret = _drm_vma_info(oidp, arg1, arg2, req);
+ lockmgr(&dev->dev_lock, LK_RELEASE, 0, curproc);
+ return ret;
+}
+#endif
+
+
+#if DRM_DMA_HISTOGRAM
+static int _drm_histo_info SYSCTL_HANDLER_ARGS
+{
+ drm_device_t *dev = arg1;
+ drm_device_dma_t *dma = dev->dma;
+ int i;
+ unsigned long slot_value = DRM_DMA_HISTOGRAM_INITIAL;
+ unsigned long prev_value = 0;
+ drm_buf_t *buffer;
+ char buf[128];
+ int error;
+
+ DRM_SYSCTL_PRINT("general statistics:\n");
+ DRM_SYSCTL_PRINT("total %10u\n", atomic_read(&dev->histo.total));
+ DRM_SYSCTL_PRINT("open %10u\n", atomic_read(&dev->total_open));
+ DRM_SYSCTL_PRINT("close %10u\n", atomic_read(&dev->total_close));
+ DRM_SYSCTL_PRINT("ioctl %10u\n", atomic_read(&dev->total_ioctl));
+ DRM_SYSCTL_PRINT("irq %10u\n", atomic_read(&dev->total_irq));
+ DRM_SYSCTL_PRINT("ctx %10u\n", atomic_read(&dev->total_ctx));
+
+ DRM_SYSCTL_PRINT("\nlock statistics:\n");
+ DRM_SYSCTL_PRINT("locks %10u\n", atomic_read(&dev->total_locks));
+ DRM_SYSCTL_PRINT("unlocks %10u\n", atomic_read(&dev->total_unlocks));
+ DRM_SYSCTL_PRINT("contends %10u\n", atomic_read(&dev->total_contends));
+ DRM_SYSCTL_PRINT("sleeps %10u\n", atomic_read(&dev->total_sleeps));
+
+
+ if (dma) {
+ DRM_SYSCTL_PRINT("\ndma statistics:\n");
+ DRM_SYSCTL_PRINT("prio %10u\n",
+ atomic_read(&dma->total_prio));
+ DRM_SYSCTL_PRINT("bytes %10u\n",
+ atomic_read(&dma->total_bytes));
+ DRM_SYSCTL_PRINT("dmas %10u\n",
+ atomic_read(&dma->total_dmas));
+ DRM_SYSCTL_PRINT("missed:\n");
+ DRM_SYSCTL_PRINT(" dma %10u\n",
+ atomic_read(&dma->total_missed_dma));
+ DRM_SYSCTL_PRINT(" lock %10u\n",
+ atomic_read(&dma->total_missed_lock));
+ DRM_SYSCTL_PRINT(" free %10u\n",
+ atomic_read(&dma->total_missed_free));
+ DRM_SYSCTL_PRINT(" sched %10u\n",
+ atomic_read(&dma->total_missed_sched));
+ DRM_SYSCTL_PRINT("tried %10u\n",
+ atomic_read(&dma->total_tried));
+ DRM_SYSCTL_PRINT("hit %10u\n",
+ atomic_read(&dma->total_hit));
+ DRM_SYSCTL_PRINT("lost %10u\n",
+ atomic_read(&dma->total_lost));
+
+ buffer = dma->next_buffer;
+ if (buffer) {
+ DRM_SYSCTL_PRINT("next_buffer %7d\n", buffer->idx);
+ } else {
+ DRM_SYSCTL_PRINT("next_buffer none\n");
+ }
+ buffer = dma->this_buffer;
+ if (buffer) {
+ DRM_SYSCTL_PRINT("this_buffer %7d\n", buffer->idx);
+ } else {
+ DRM_SYSCTL_PRINT("this_buffer none\n");
+ }
+ }
+
+
+ DRM_SYSCTL_PRINT("\nvalues:\n");
+ if (dev->lock.hw_lock) {
+ DRM_SYSCTL_PRINT("lock 0x%08x\n",
+ dev->lock.hw_lock->lock);
+ } else {
+ DRM_SYSCTL_PRINT("lock none\n");
+ }
+ DRM_SYSCTL_PRINT("context_flag 0x%08x\n", dev->context_flag);
+ DRM_SYSCTL_PRINT("interrupt_flag 0x%08x\n", dev->interrupt_flag);
+ DRM_SYSCTL_PRINT("dma_flag 0x%08x\n", dev->dma_flag);
+
+ DRM_SYSCTL_PRINT("queue_count %10d\n", dev->queue_count);
+ DRM_SYSCTL_PRINT("last_context %10d\n", dev->last_context);
+ DRM_SYSCTL_PRINT("last_switch %10u\n", dev->last_switch);
+ DRM_SYSCTL_PRINT("last_checked %10d\n", dev->last_checked);
+
+
+ DRM_SYSCTL_PRINT("\n q2d d2c c2f"
+ " q2c q2f dma sch"
+ " ctx lacq lhld\n\n");
+ for (i = 0; i < DRM_DMA_HISTOGRAM_SLOTS; i++) {
+ DRM_SYSCTL_PRINT("%s %10lu %10u %10u %10u %10u %10u"
+ " %10u %10u %10u %10u %10u\n",
+ i == DRM_DMA_HISTOGRAM_SLOTS - 1 ? ">=" : "< ",
+ i == DRM_DMA_HISTOGRAM_SLOTS - 1
+ ? prev_value : slot_value ,
+
+ atomic_read(&dev->histo
+ .queued_to_dispatched[i]),
+ atomic_read(&dev->histo
+ .dispatched_to_completed[i]),
+ atomic_read(&dev->histo
+ .completed_to_freed[i]),
+
+ atomic_read(&dev->histo
+ .queued_to_completed[i]),
+ atomic_read(&dev->histo
+ .queued_to_freed[i]),
+ atomic_read(&dev->histo.dma[i]),
+ atomic_read(&dev->histo.schedule[i]),
+ atomic_read(&dev->histo.ctx[i]),
+ atomic_read(&dev->histo.lacq[i]),
+ atomic_read(&dev->histo.lhld[i]));
+ prev_value = slot_value;
+ slot_value = DRM_DMA_HISTOGRAM_NEXT(slot_value);
+ }
+ SYSCTL_OUT(req, "", 1);
+ return 0;
+}
+
+static int drm_histo_info SYSCTL_HANDLER_ARGS
+{
+ drm_device_t *dev = arg1;
+ int ret;
+
+ lockmgr(&dev->dev_lock, LK_EXCLUSIVE, 0, curproc);
+ ret = _drm_histo_info(oidp, arg1, arg2, req);
+ lockmgr(&dev->dev_lock, LK_RELEASE, 0, curproc);
+ return ret;
+}
+#endif
diff --git a/bsd/drm/vm.c b/bsd/drm/vm.c
new file mode 100644
index 00000000..9c457fca
--- /dev/null
+++ b/bsd/drm/vm.c
@@ -0,0 +1,104 @@
+/* vm.c -- Memory mapping for DRM -*- c -*-
+ * Created: Mon Jan 4 08:58:31 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 22:48:11 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/vm.c,v 1.7 1999/08/21 02:48:34 faith Exp $
+ * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/vm.c,v 1.1 1999/09/25 14:38:02 dawes Exp $
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+static int drm_dma_mmap(dev_t kdev, vm_offset_t offset, int prot)
+{
+ drm_device_t *dev = kdev->si_drv1;
+ drm_device_dma_t *dma = dev->dma;
+ unsigned long physical;
+ unsigned long page;
+
+ if (!dma) return -1; /* Error */
+ if (!dma->pagelist) return -1; /* Nothing allocated */
+
+ page = offset >> PAGE_SHIFT;
+ physical = dma->pagelist[page];
+
+ DRM_DEBUG("0x%08x (page %lu) => 0x%08lx\n", offset, page, physical);
+ return atop(physical);
+}
+
+int drm_mmap(dev_t kdev, vm_offset_t offset, int prot)
+{
+ drm_device_t *dev = kdev->si_drv1;
+ drm_map_t *map = NULL;
+ int i;
+
+ /* DRM_DEBUG("offset = 0x%x\n", offset); */
+
+ if (dev->dma
+ && offset >= 0
+ && offset < ptoa(dev->dma->page_count))
+ return drm_dma_mmap(kdev, offset, prot);
+
+ /* A sequential search of a linked list is
+ fine here because: 1) there will only be
+ about 5-10 entries in the list and, 2) a
+ DRI client only has to do this mapping
+ once, so it doesn't have to be optimized
+ for performance, even if the list was a
+ bit longer. */
+ for (i = 0; i < dev->map_count; i++) {
+ map = dev->maplist[i];
+ /* DRM_DEBUG("considering 0x%x..0x%x\n", map->offset, map->offset + map->size - 1); */
+ if (offset >= map->offset
+ && offset < map->offset + map->size) break;
+ }
+
+ if (i >= dev->map_count) {
+ DRM_DEBUG("can't find map\n");
+ return -1;
+ }
+ if (!map || ((map->flags&_DRM_RESTRICTED) && suser(curproc))) {
+ DRM_DEBUG("restricted map\n");
+ return -1;
+ }
+
+ switch (map->type) {
+ case _DRM_FRAME_BUFFER:
+ case _DRM_REGISTERS:
+ case _DRM_AGP:
+ return atop(offset);
+ case _DRM_SHM:
+ return atop(vtophys(offset));
+ default:
+ return -1; /* This should never happen. */
+ }
+ DRM_DEBUG("bailing out\n");
+
+ return -1;
+}