libdrm 2.4.37 nouveau 1
authorNikhil Devshatwar <a0132237@ti.com>
Fri, 17 May 2013 09:51:30 +0000 (15:21 +0530)
committerNikhil Devshatwar <a0132237@ti.com>
Fri, 17 May 2013 09:51:30 +0000 (15:21 +0530)
24 files changed:
Makefile.am
configure.ac
nouveau-1/Makefile.am [new file with mode: 0644]
nouveau-1/libdrm_nouveau1.pc.in [new file with mode: 0644]
nouveau-1/nouveau_bo.c [new file with mode: 0644]
nouveau-1/nouveau_bo.h [new file with mode: 0644]
nouveau-1/nouveau_channel.c [new file with mode: 0644]
nouveau-1/nouveau_channel.h [new file with mode: 0644]
nouveau-1/nouveau_device.c [new file with mode: 0644]
nouveau-1/nouveau_device.h [new file with mode: 0644]
nouveau-1/nouveau_drmif.h [new file with mode: 0644]
nouveau-1/nouveau_grobj.c [new file with mode: 0644]
nouveau-1/nouveau_grobj.h [new file with mode: 0644]
nouveau-1/nouveau_notifier.c [new file with mode: 0644]
nouveau-1/nouveau_notifier.h [new file with mode: 0644]
nouveau-1/nouveau_private.h [new file with mode: 0644]
nouveau-1/nouveau_pushbuf.c [new file with mode: 0644]
nouveau-1/nouveau_pushbuf.h [new file with mode: 0644]
nouveau-1/nouveau_reloc.c [new file with mode: 0644]
nouveau-1/nouveau_reloc.h [new file with mode: 0644]
nouveau-1/nouveau_resource.c [new file with mode: 0644]
nouveau-1/nouveau_resource.h [new file with mode: 0644]
nouveau-1/nv04_pushbuf.h [new file with mode: 0644]
nouveau-1/nvc0_pushbuf.h [new file with mode: 0644]

index 9f106d395666cb59d9358533fd35456ce52af0fa..e6cd0f5f87c51430e483a2638a6fa34430f79aed 100644 (file)
@@ -34,7 +34,7 @@ INTEL_SUBDIR = intel
 endif
 
 if HAVE_NOUVEAU
-NOUVEAU_SUBDIR = nouveau
+NOUVEAU_SUBDIR = nouveau-1 nouveau
 endif
 
 if HAVE_RADEON
index 10cc9a42be59b8d3aa135c4620911e12e02054d9..9f06cc5f06e49d58e8a9ede33f5a0cac2146c2af 100644 (file)
@@ -334,6 +334,8 @@ AC_CONFIG_FILES([
        intel/libdrm_intel.pc
        radeon/Makefile
        radeon/libdrm_radeon.pc
+       nouveau-1/Makefile
+       nouveau-1/libdrm_nouveau1.pc
        nouveau/Makefile
        nouveau/libdrm_nouveau.pc
        omap/Makefile
diff --git a/nouveau-1/Makefile.am b/nouveau-1/Makefile.am
new file mode 100644 (file)
index 0000000..ca46c4b
--- /dev/null
@@ -0,0 +1,43 @@
+AM_CFLAGS = \
+       $(WARN_CFLAGS) \
+       -I$(top_srcdir) \
+       -I$(top_srcdir)/nouveau-1 \
+       $(PTHREADSTUBS_CFLAGS) \
+       -I$(top_srcdir)/include/drm
+
+libdrm_nouveau_la_LTLIBRARIES = libdrm_nouveau.la
+libdrm_nouveau_ladir = $(libdir)
+libdrm_nouveau_la_LDFLAGS = -version-number 1:0:0 -no-undefined
+libdrm_nouveau_la_LIBADD = ../libdrm.la @PTHREADSTUBS_LIBS@
+
+libdrm_nouveau_la_SOURCES = \
+                           nouveau_device.c \
+                           nouveau_channel.c \
+                           nouveau_pushbuf.c \
+                           nouveau_grobj.c \
+                           nouveau_notifier.c \
+                           nouveau_bo.c \
+                           nouveau_resource.c \
+                           nouveau_private.h \
+                           nouveau_reloc.c
+
+libdrm_nouveaucommonincludedir = ${includedir}/nouveau
+libdrm_nouveaucommoninclude_HEADERS = \
+                               nouveau_device.h \
+                               nouveau_channel.h \
+                               nouveau_grobj.h \
+                               nouveau_notifier.h \
+                               nouveau_pushbuf.h \
+                               nv04_pushbuf.h \
+                               nvc0_pushbuf.h \
+                               nouveau_bo.h \
+                               nouveau_resource.h \
+                               nouveau_reloc.h
+
+
+libdrm_nouveauincludedir = ${includedir}/libdrm
+libdrm_nouveauinclude_HEADERS = \
+                               nouveau_drmif.h
+
+pkgconfigdir = @pkgconfigdir@
+pkgconfig_DATA = libdrm_nouveau1.pc
diff --git a/nouveau-1/libdrm_nouveau1.pc.in b/nouveau-1/libdrm_nouveau1.pc.in
new file mode 100644 (file)
index 0000000..6e3c771
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libdrm_nouveau
+Description: Userspace interface to nouveau kernel DRM services
+Version: 0.6
+Libs: -L${libdir} -ldrm_nouveau1
+Cflags: -I${includedir} -I${includedir}/libdrm -I${includedir}/nouveau
+Requires.private: libdrm
diff --git a/nouveau-1/nouveau_bo.c b/nouveau-1/nouveau_bo.c
new file mode 100644 (file)
index 0000000..d6bb22d
--- /dev/null
@@ -0,0 +1,549 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdint.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <sys/mman.h>
+
+#include "nouveau_private.h"
+
+int
+nouveau_bo_init(struct nouveau_device *dev)
+{
+       return 0;
+}
+
+void
+nouveau_bo_takedown(struct nouveau_device *dev)
+{
+}
+
+static int
+nouveau_bo_info(struct nouveau_bo_priv *nvbo, struct drm_nouveau_gem_info *arg)
+{
+       nvbo->handle = nvbo->base.handle = arg->handle;
+       nvbo->domain = arg->domain;
+       nvbo->size = arg->size;
+       nvbo->offset = arg->offset;
+       nvbo->map_handle = arg->map_handle;
+       nvbo->base.tile_mode = arg->tile_mode;
+       /* XXX - flag inverted for backwards compatibility */
+       nvbo->base.tile_flags = arg->tile_flags ^ NOUVEAU_GEM_TILE_NONCONTIG;
+       return 0;
+}
+
+static int
+nouveau_bo_allocated(struct nouveau_bo_priv *nvbo)
+{
+       if (nvbo->sysmem || nvbo->handle)
+               return 1;
+       return 0;
+}
+
+static int
+nouveau_bo_ualloc(struct nouveau_bo_priv *nvbo)
+{
+       if (nvbo->user || nvbo->sysmem) {
+               assert(nvbo->sysmem);
+               return 0;
+       }
+
+       nvbo->sysmem = malloc(nvbo->size);
+       if (!nvbo->sysmem)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static void
+nouveau_bo_ufree(struct nouveau_bo_priv *nvbo)
+{
+       if (nvbo->sysmem) {
+               if (!nvbo->user)
+                       free(nvbo->sysmem);
+               nvbo->sysmem = NULL;
+       }
+}
+
+static void
+nouveau_bo_kfree(struct nouveau_bo_priv *nvbo)
+{
+       struct nouveau_device_priv *nvdev = nouveau_device(nvbo->base.device);
+       struct drm_gem_close req;
+
+       if (!nvbo->handle)
+               return;
+
+       if (nvbo->map) {
+               munmap(nvbo->map, nvbo->size);
+               nvbo->map = NULL;
+       }
+
+       req.handle = nvbo->handle;
+       nvbo->handle = 0;
+       drmIoctl(nvdev->fd, DRM_IOCTL_GEM_CLOSE, &req);
+}
+
+static int
+nouveau_bo_kalloc(struct nouveau_bo_priv *nvbo, struct nouveau_channel *chan)
+{
+       struct nouveau_device_priv *nvdev = nouveau_device(nvbo->base.device);
+       struct drm_nouveau_gem_new req;
+       struct drm_nouveau_gem_info *info = &req.info;
+       int ret;
+
+       if (nvbo->handle)
+               return 0;
+
+       req.channel_hint = chan ? chan->id : 0;
+       req.align = nvbo->align;
+
+
+       info->size = nvbo->size;
+       info->domain = 0;
+
+       if (nvbo->flags & NOUVEAU_BO_VRAM)
+               info->domain |= NOUVEAU_GEM_DOMAIN_VRAM;
+       if (nvbo->flags & NOUVEAU_BO_GART)
+               info->domain |= NOUVEAU_GEM_DOMAIN_GART;
+       if (!info->domain) {
+               info->domain |= (NOUVEAU_GEM_DOMAIN_VRAM |
+                                NOUVEAU_GEM_DOMAIN_GART);
+       }
+
+       if (nvbo->flags & NOUVEAU_BO_MAP)
+               info->domain |= NOUVEAU_GEM_DOMAIN_MAPPABLE;
+
+       info->tile_mode = nvbo->base.tile_mode;
+       info->tile_flags = nvbo->base.tile_flags;
+       /* XXX - flag inverted for backwards compatibility */
+       info->tile_flags ^= NOUVEAU_GEM_TILE_NONCONTIG;
+       if (!nvdev->has_bo_usage)
+               info->tile_flags &= NOUVEAU_GEM_TILE_LAYOUT_MASK;
+
+       ret = drmCommandWriteRead(nvdev->fd, DRM_NOUVEAU_GEM_NEW,
+                                 &req, sizeof(req));
+       if (ret)
+               return ret;
+
+       nouveau_bo_info(nvbo, &req.info);
+       return 0;
+}
+
+static int
+nouveau_bo_kmap(struct nouveau_bo_priv *nvbo)
+{
+       struct nouveau_device_priv *nvdev = nouveau_device(nvbo->base.device);
+
+       if (nvbo->map)
+               return 0;
+
+       if (!nvbo->map_handle)
+               return -EINVAL;
+
+       nvbo->map = mmap(0, nvbo->size, PROT_READ | PROT_WRITE,
+                        MAP_SHARED, nvdev->fd, nvbo->map_handle);
+       if (nvbo->map == MAP_FAILED) {
+               nvbo->map = NULL;
+               return -errno;
+       }
+
+       return 0;
+}
+
+int
+nouveau_bo_new_tile(struct nouveau_device *dev, uint32_t flags, int align,
+                   int size, uint32_t tile_mode, uint32_t tile_flags,
+                   struct nouveau_bo **bo)
+{
+       struct nouveau_bo_priv *nvbo;
+       int ret;
+
+       if (!dev || !bo || *bo)
+               return -EINVAL;
+
+       nvbo = calloc(1, sizeof(struct nouveau_bo_priv));
+       if (!nvbo)
+               return -ENOMEM;
+       nvbo->base.device = dev;
+       nvbo->base.size = size;
+       nvbo->base.tile_mode = tile_mode;
+       nvbo->base.tile_flags = tile_flags;
+
+       nvbo->refcount = 1;
+       nvbo->flags = flags;
+       nvbo->size = size;
+       nvbo->align = align;
+
+       if (flags & (NOUVEAU_BO_VRAM | NOUVEAU_BO_GART)) {
+               ret = nouveau_bo_kalloc(nvbo, NULL);
+               if (ret) {
+                       nouveau_bo_ref(NULL, (void *)&nvbo);
+                       return ret;
+               }
+       }
+
+       *bo = &nvbo->base;
+       return 0;
+}
+
+int
+nouveau_bo_new(struct nouveau_device *dev, uint32_t flags, int align,
+              int size, struct nouveau_bo **bo)
+{
+       return nouveau_bo_new_tile(dev, flags, align, size, 0, 0, bo);
+}
+
+int
+nouveau_bo_user(struct nouveau_device *dev, void *ptr, int size,
+               struct nouveau_bo **bo)
+{
+       struct nouveau_bo_priv *nvbo;
+       int ret;
+
+       ret = nouveau_bo_new(dev, NOUVEAU_BO_MAP, 0, size, bo);
+       if (ret)
+               return ret;
+       nvbo = nouveau_bo(*bo);
+
+       nvbo->sysmem = ptr;
+       nvbo->user = 1;
+       return 0;
+}
+
+int
+nouveau_bo_wrap(struct nouveau_device *dev, uint32_t handle,
+               struct nouveau_bo **bo)
+{
+       struct nouveau_device_priv *nvdev = nouveau_device(dev);
+       struct drm_nouveau_gem_info req;
+       struct nouveau_bo_priv *nvbo;
+       int ret;
+
+       ret = nouveau_bo_new(dev, 0, 0, 0, bo);
+       if (ret)
+               return ret;
+       nvbo = nouveau_bo(*bo);
+
+       req.handle = handle;
+       ret = drmCommandWriteRead(nvdev->fd, DRM_NOUVEAU_GEM_INFO,
+                                 &req, sizeof(req));
+       if (ret) {
+               nouveau_bo_ref(NULL, bo);
+               return ret;
+       }
+
+       nouveau_bo_info(nvbo, &req);
+       nvbo->base.size = nvbo->size;
+       return 0;
+}
+
+int
+nouveau_bo_handle_get(struct nouveau_bo *bo, uint32_t *handle)
+{
+       struct nouveau_device_priv *nvdev = nouveau_device(bo->device);
+       struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
+       int ret;
+       if (!bo || !handle)
+               return -EINVAL;
+
+       if (!nvbo->global_handle) {
+               struct drm_gem_flink req;
+               ret = nouveau_bo_kalloc(nvbo, NULL);
+               if (ret)
+                       return ret;
+
+               req.handle = nvbo->handle;
+               ret = drmIoctl(nvdev->fd, DRM_IOCTL_GEM_FLINK, &req);
+               if (ret) {
+                       nouveau_bo_kfree(nvbo);
+                       return ret;
+               }
+
+               nvbo->global_handle = req.name;
+       }
+       *handle = nvbo->global_handle;
+       return 0;
+}
+int
+nouveau_bo_handle_ref(struct nouveau_device *dev, uint32_t handle,
+                     struct nouveau_bo **bo)
+{
+       struct nouveau_device_priv *nvdev = nouveau_device(dev);
+       struct nouveau_bo_priv *nvbo;
+       struct drm_gem_open req;
+       int ret;
+
+       req.name = handle;
+       ret = drmIoctl(nvdev->fd, DRM_IOCTL_GEM_OPEN, &req);
+       if (ret) {
+               nouveau_bo_ref(NULL, bo);
+               return ret;
+       }
+
+       ret = nouveau_bo_wrap(dev, req.handle, bo);
+       if (ret) {
+               nouveau_bo_ref(NULL, bo);
+               return ret;
+       }
+
+       nvbo = nouveau_bo(*bo);
+       nvbo->base.handle = nvbo->handle;
+       return 0;
+} 
+
+static void
+nouveau_bo_del(struct nouveau_bo **bo)
+{
+       struct nouveau_bo_priv *nvbo;
+
+       if (!bo || !*bo)
+               return;
+       nvbo = nouveau_bo(*bo);
+       *bo = NULL;
+
+       if (--nvbo->refcount)
+               return;
+
+       if (nvbo->pending) {
+               nvbo->pending = NULL;
+               nouveau_pushbuf_flush(nvbo->pending_channel, 0);
+       }
+
+       nouveau_bo_ufree(nvbo);
+       nouveau_bo_kfree(nvbo);
+       free(nvbo);
+}
+
+int
+nouveau_bo_ref(struct nouveau_bo *ref, struct nouveau_bo **pbo)
+{
+       if (!pbo)
+               return -EINVAL;
+
+       if (ref)
+               nouveau_bo(ref)->refcount++;
+
+       if (*pbo)
+               nouveau_bo_del(pbo);
+
+       *pbo = ref;
+       return 0;
+}
+
+static int
+nouveau_bo_wait(struct nouveau_bo *bo, int cpu_write, int no_wait, int no_block)
+{
+       struct nouveau_device_priv *nvdev = nouveau_device(bo->device);
+       struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
+       struct drm_nouveau_gem_cpu_prep req;
+       int ret;
+
+       if (!nvbo->global_handle && !nvbo->write_marker && !cpu_write)
+               return 0;
+
+       if (nvbo->pending &&
+           (nvbo->pending->write_domains || cpu_write)) {
+               nvbo->pending = NULL;
+               nouveau_pushbuf_flush(nvbo->pending_channel, 0);
+       }
+
+       req.handle = nvbo->handle;
+       req.flags = 0;
+       if (cpu_write)
+               req.flags |= NOUVEAU_GEM_CPU_PREP_WRITE;
+       if (no_wait)
+               req.flags |= NOUVEAU_GEM_CPU_PREP_NOWAIT;
+       if (no_block)
+               req.flags |= NOUVEAU_GEM_CPU_PREP_NOBLOCK;
+
+       do {
+               ret = drmCommandWrite(nvdev->fd, DRM_NOUVEAU_GEM_CPU_PREP,
+                                     &req, sizeof(req));
+       } while (ret == -EAGAIN);
+       if (ret)
+               return ret;
+
+       if (ret == 0)
+               nvbo->write_marker = 0;
+       return 0;
+}
+
+int
+nouveau_bo_map_range(struct nouveau_bo *bo, uint32_t delta, uint32_t size,
+                    uint32_t flags)
+{
+       struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
+       int ret;
+
+       if (!nvbo || bo->map)
+               return -EINVAL;
+
+       if (!nouveau_bo_allocated(nvbo)) {
+               if (nvbo->flags & (NOUVEAU_BO_VRAM | NOUVEAU_BO_GART)) {
+                       ret = nouveau_bo_kalloc(nvbo, NULL);
+                       if (ret)
+                               return ret;
+               }
+
+               if (!nouveau_bo_allocated(nvbo)) {
+                       ret = nouveau_bo_ualloc(nvbo);
+                       if (ret)
+                               return ret;
+               }
+       }
+
+       if (nvbo->sysmem) {
+               bo->map = (char *)nvbo->sysmem + delta;
+       } else {
+               ret = nouveau_bo_kmap(nvbo);
+               if (ret)
+                       return ret;
+
+               if (!(flags & NOUVEAU_BO_NOSYNC)) {
+                       ret = nouveau_bo_wait(bo, (flags & NOUVEAU_BO_WR),
+                                             (flags & NOUVEAU_BO_NOWAIT), 0);
+                       if (ret)
+                               return ret;
+
+                       nvbo->map_refcnt++;
+               }
+
+               bo->map = (char *)nvbo->map + delta;
+       }
+
+       return 0;
+}
+
+void
+nouveau_bo_map_flush(struct nouveau_bo *bo, uint32_t delta, uint32_t size)
+{
+}
+
+int
+nouveau_bo_map(struct nouveau_bo *bo, uint32_t flags)
+{
+       return nouveau_bo_map_range(bo, 0, bo->size, flags);
+}
+
+void
+nouveau_bo_unmap(struct nouveau_bo *bo)
+{
+       struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
+
+       if (bo->map && !nvbo->sysmem && nvbo->map_refcnt) {
+               struct nouveau_device_priv *nvdev = nouveau_device(bo->device);
+               struct drm_nouveau_gem_cpu_fini req;
+
+               req.handle = nvbo->handle;
+               drmCommandWrite(nvdev->fd, DRM_NOUVEAU_GEM_CPU_FINI,
+                               &req, sizeof(req));
+               nvbo->map_refcnt--;
+       }
+
+       bo->map = NULL;
+}
+
+int
+nouveau_bo_busy(struct nouveau_bo *bo, uint32_t access)
+{
+       return nouveau_bo_wait(bo, (access & NOUVEAU_BO_WR), 1, 1);
+}
+
+uint32_t
+nouveau_bo_pending(struct nouveau_bo *bo)
+{
+       struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
+       uint32_t flags;
+
+       if (!nvbo->pending)
+               return 0;
+
+       flags = 0;
+       if (nvbo->pending->read_domains)
+               flags |= NOUVEAU_BO_RD;
+       if (nvbo->pending->write_domains)
+               flags |= NOUVEAU_BO_WR;
+
+       return flags;
+}
+
+struct drm_nouveau_gem_pushbuf_bo *
+nouveau_bo_emit_buffer(struct nouveau_channel *chan, struct nouveau_bo *bo)
+{
+       struct nouveau_pushbuf_priv *nvpb = &nouveau_channel(chan)->pb;
+       struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
+       struct drm_nouveau_gem_pushbuf_bo *pbbo;
+       struct nouveau_bo *ref = NULL;
+       int ret;
+
+       if (nvbo->pending)
+               return nvbo->pending;
+
+       if (!nvbo->handle) {
+               ret = nouveau_bo_kalloc(nvbo, chan);
+               if (ret)
+                       return NULL;
+
+               if (nvbo->sysmem) {
+                       void *sysmem_tmp = nvbo->sysmem;
+
+                       nvbo->sysmem = NULL;
+                       ret = nouveau_bo_map(bo, NOUVEAU_BO_WR);
+                       if (ret)
+                               return NULL;
+                       nvbo->sysmem = sysmem_tmp;
+
+                       memcpy(bo->map, nvbo->sysmem, nvbo->base.size);
+                       nouveau_bo_ufree(nvbo);
+                       nouveau_bo_unmap(bo);
+               }
+       }
+
+       if (nvpb->nr_buffers >= NOUVEAU_GEM_MAX_BUFFERS)
+               return NULL;
+       pbbo = nvpb->buffers + nvpb->nr_buffers++;
+       nvbo->pending = pbbo;
+       nvbo->pending_channel = chan;
+       nvbo->pending_refcnt = 0;
+
+       nouveau_bo_ref(bo, &ref);
+       pbbo->user_priv = (uint64_t)(unsigned long)ref;
+       pbbo->handle = nvbo->handle;
+       pbbo->valid_domains = NOUVEAU_GEM_DOMAIN_VRAM | NOUVEAU_GEM_DOMAIN_GART;
+       pbbo->read_domains = 0;
+       pbbo->write_domains = 0;
+       pbbo->presumed.domain = nvbo->domain;
+       pbbo->presumed.offset = nvbo->offset;
+       pbbo->presumed.valid = 1;
+       return pbbo;
+}
diff --git a/nouveau-1/nouveau_bo.h b/nouveau-1/nouveau_bo.h
new file mode 100644 (file)
index 0000000..3a1f2d4
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __NOUVEAU_BO_H__
+#define __NOUVEAU_BO_H__
+
+/* Relocation/Buffer type flags */
+#define NOUVEAU_BO_VRAM   (1 << 0)
+#define NOUVEAU_BO_GART   (1 << 1)
+#define NOUVEAU_BO_RD     (1 << 2)
+#define NOUVEAU_BO_WR     (1 << 3)
+#define NOUVEAU_BO_RDWR   (NOUVEAU_BO_RD | NOUVEAU_BO_WR)
+#define NOUVEAU_BO_MAP    (1 << 4)
+#define NOUVEAU_BO_LOW    (1 << 6)
+#define NOUVEAU_BO_HIGH   (1 << 7)
+#define NOUVEAU_BO_OR     (1 << 8)
+#define NOUVEAU_BO_INVAL  (1 << 12)
+#define NOUVEAU_BO_NOSYNC (1 << 13)
+#define NOUVEAU_BO_NOWAIT (1 << 14)
+#define NOUVEAU_BO_IFLUSH (1 << 15)
+#define NOUVEAU_BO_DUMMY  (1 << 31)
+
+#define NOUVEAU_BO_TILE_LAYOUT_MASK 0x0000ff00
+#define NOUVEAU_BO_TILE_16BPP       0x00000001
+#define NOUVEAU_BO_TILE_32BPP       0x00000002
+#define NOUVEAU_BO_TILE_ZETA        0x00000004
+#define NOUVEAU_BO_TILE_SCANOUT     0x00000008
+
+struct nouveau_bo {
+       struct nouveau_device *device;
+       uint32_t handle;
+
+       uint64_t size;
+       void *map;
+
+       uint32_t tile_mode;
+       uint32_t tile_flags;
+};
+
+int
+nouveau_bo_new(struct nouveau_device *, uint32_t flags, int align, int size,
+              struct nouveau_bo **);
+
+int
+nouveau_bo_new_tile(struct nouveau_device *, uint32_t flags, int align,
+                   int size, uint32_t tile_mode, uint32_t tile_flags,
+                   struct nouveau_bo **);
+
+int
+nouveau_bo_user(struct nouveau_device *, void *ptr, int size,
+               struct nouveau_bo **);
+
+int
+nouveau_bo_wrap(struct nouveau_device *, uint32_t handle, struct nouveau_bo **);
+
+int
+nouveau_bo_handle_get(struct nouveau_bo *, uint32_t *);
+
+int
+nouveau_bo_handle_ref(struct nouveau_device *, uint32_t handle,
+                     struct nouveau_bo **);
+
+int
+nouveau_bo_ref(struct nouveau_bo *, struct nouveau_bo **);
+
+int
+nouveau_bo_map_range(struct nouveau_bo *, uint32_t delta, uint32_t size,
+                    uint32_t flags);
+
+void
+nouveau_bo_map_flush(struct nouveau_bo *, uint32_t delta, uint32_t size);
+
+int
+nouveau_bo_map(struct nouveau_bo *, uint32_t flags);
+
+void
+nouveau_bo_unmap(struct nouveau_bo *);
+
+int
+nouveau_bo_busy(struct nouveau_bo *, uint32_t access);
+
+uint32_t
+nouveau_bo_pending(struct nouveau_bo *);
+
+#endif
diff --git a/nouveau-1/nouveau_channel.c b/nouveau-1/nouveau_channel.c
new file mode 100644 (file)
index 0000000..96fa03b
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS 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.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "nouveau_private.h"
+
+int
+nouveau_channel_alloc(struct nouveau_device *dev, uint32_t fb_ctxdma,
+                     uint32_t tt_ctxdma, int pushbuf_size,
+                     struct nouveau_channel **chan)
+{
+       struct nouveau_device_priv *nvdev = nouveau_device(dev);
+       struct nouveau_channel_priv *nvchan;
+       unsigned i;
+       int ret;
+
+       if (!nvdev || !chan || *chan)
+           return -EINVAL;
+
+       nvchan = calloc(1, sizeof(struct nouveau_channel_priv));
+       if (!nvchan)
+               return -ENOMEM;
+       nvchan->base.device = dev;
+
+       nvchan->drm.fb_ctxdma_handle = fb_ctxdma;
+       nvchan->drm.tt_ctxdma_handle = tt_ctxdma;
+       ret = drmCommandWriteRead(nvdev->fd, DRM_NOUVEAU_CHANNEL_ALLOC,
+                                 &nvchan->drm, sizeof(nvchan->drm));
+       if (ret) {
+               free(nvchan);
+               return ret;
+       }
+
+       nvchan->base.id = nvchan->drm.channel;
+       if (nouveau_grobj_ref(&nvchan->base, nvchan->drm.fb_ctxdma_handle,
+                             &nvchan->base.vram) ||
+           nouveau_grobj_ref(&nvchan->base, nvchan->drm.tt_ctxdma_handle,
+                             &nvchan->base.gart)) {
+               nouveau_channel_free((void *)&nvchan);
+               return -EINVAL;
+       }
+
+       /* Mark all DRM-assigned subchannels as in-use */
+       for (i = 0; i < nvchan->drm.nr_subchan; i++) {
+               struct nouveau_grobj_priv *gr = calloc(1, sizeof(*gr));
+
+               gr->base.bound = NOUVEAU_GROBJ_BOUND_EXPLICIT;
+               gr->base.subc = i;
+               gr->base.handle = nvchan->drm.subchan[i].handle;
+               gr->base.grclass = nvchan->drm.subchan[i].grclass;
+               gr->base.channel = &nvchan->base;
+
+               nvchan->base.subc[i].gr = &gr->base;
+       }
+
+       if (dev->chipset < 0xc0) {
+               ret = nouveau_bo_wrap(dev, nvchan->drm.notifier_handle,
+                                     &nvchan->notifier_bo);
+               if (!ret)
+                       ret = nouveau_bo_map(nvchan->notifier_bo,
+                                            NOUVEAU_BO_RDWR);
+               if (ret) {
+                       nouveau_channel_free((void *)&nvchan);
+                       return ret;
+               }
+
+               ret = nouveau_grobj_alloc(&nvchan->base, 0x00000000, 0x0030,
+                                         &nvchan->base.nullobj);
+               if (ret) {
+                       nouveau_channel_free((void *)&nvchan);
+                       return ret;
+               }
+       }
+
+       ret = nouveau_pushbuf_init(&nvchan->base, pushbuf_size);
+       if (ret) {
+               nouveau_channel_free((void *)&nvchan);
+               return ret;
+       }
+
+       *chan = &nvchan->base;
+       return 0;
+}
+
+void
+nouveau_channel_free(struct nouveau_channel **chan)
+{
+       struct nouveau_channel_priv *nvchan;
+       struct nouveau_device_priv *nvdev;
+       struct drm_nouveau_channel_free cf;
+       unsigned i;
+
+       if (!chan || !*chan)
+               return;
+       nvchan = nouveau_channel(*chan);
+       (*chan)->flush_notify = NULL;
+       *chan = NULL;
+       nvdev = nouveau_device(nvchan->base.device);
+
+       FIRE_RING(&nvchan->base);
+
+       nouveau_pushbuf_fini(&nvchan->base);
+       if (nvchan->notifier_bo) {
+               nouveau_bo_unmap(nvchan->notifier_bo);
+               nouveau_bo_ref(NULL, &nvchan->notifier_bo);
+       }
+
+       for (i = 0; i < nvchan->drm.nr_subchan; i++)
+               free(nvchan->base.subc[i].gr);
+
+       nouveau_grobj_free(&nvchan->base.vram);
+       nouveau_grobj_free(&nvchan->base.gart);
+       nouveau_grobj_free(&nvchan->base.nullobj);
+
+       cf.channel = nvchan->drm.channel;
+       drmCommandWrite(nvdev->fd, DRM_NOUVEAU_CHANNEL_FREE, &cf, sizeof(cf));
+       free(nvchan);
+}
+
+
diff --git a/nouveau-1/nouveau_channel.h b/nouveau-1/nouveau_channel.h
new file mode 100644 (file)
index 0000000..d61a4c0
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __NOUVEAU_CHANNEL_H__
+#define __NOUVEAU_CHANNEL_H__
+
+struct nouveau_subchannel {
+       struct nouveau_grobj *gr;
+       unsigned sequence;
+};
+
+struct nouveau_channel {
+       uint32_t *cur;
+       uint32_t *end;
+
+       struct nouveau_device *device;
+       int id;
+
+       struct nouveau_grobj *nullobj;
+       struct nouveau_grobj *vram;
+       struct nouveau_grobj *gart;
+
+       void *user_private;
+       void (*hang_notify)(struct nouveau_channel *);
+       void (*flush_notify)(struct nouveau_channel *);
+
+       struct nouveau_subchannel subc[8];
+       unsigned subc_sequence;
+};
+
+int
+nouveau_channel_alloc(struct nouveau_device *, uint32_t fb, uint32_t tt,
+                     int pushbuf_size, struct nouveau_channel **);
+
+void
+nouveau_channel_free(struct nouveau_channel **);
+
+#endif
diff --git a/nouveau-1/nouveau_device.c b/nouveau-1/nouveau_device.c
new file mode 100644 (file)
index 0000000..425c5d2
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "nouveau_private.h"
+
+int
+nouveau_device_open_existing(struct nouveau_device **dev, int close,
+                            int fd, drm_context_t ctx)
+{
+       struct nouveau_device_priv *nvdev;
+       drmVersionPtr ver;
+       uint64_t value;
+       int ret;
+
+       if (!dev || *dev)
+           return -EINVAL;
+
+       nvdev = calloc(1, sizeof(*nvdev));
+       if (!nvdev)
+           return -ENOMEM;
+       nvdev->fd = fd;
+       nvdev->ctx = ctx;
+       nvdev->needs_close = close;
+
+       ver = drmGetVersion(fd);
+       if (!ver) {
+               nouveau_device_close((void *)&nvdev);
+               return -EINVAL;
+       }
+
+       if ((ver->version_major == 0 && ver->version_patchlevel != 16) ||
+            ver->version_major > 1) {
+               nouveau_device_close((void *)&nvdev);
+               return -EINVAL;
+       }
+
+       drmFreeVersion(ver);
+
+       ret = nouveau_device_get_param(&nvdev->base,
+                                      NOUVEAU_GETPARAM_VM_VRAM_BASE, &value);
+       if (ret) {
+               nouveau_device_close((void *)&nvdev);
+               return ret;
+       }
+       nvdev->base.vm_vram_base = value;
+
+       ret = nouveau_device_get_param(&nvdev->base,
+                                      NOUVEAU_GETPARAM_FB_SIZE, &value);
+       if (ret) {
+               nouveau_device_close((void *)&nvdev);
+               return ret;
+       }
+       nvdev->base.vm_vram_size = value;
+
+       ret = nouveau_device_get_param(&nvdev->base,
+                                      NOUVEAU_GETPARAM_AGP_SIZE, &value);
+       if (ret) {
+               nouveau_device_close((void *)&nvdev);
+               return ret;
+       }
+       nvdev->base.vm_gart_size = value;
+
+       ret = nouveau_bo_init(&nvdev->base);
+       if (ret) {
+               nouveau_device_close((void *)&nvdev);
+               return ret;
+       }
+
+       ret = nouveau_device_get_param(&nvdev->base,
+                                      NOUVEAU_GETPARAM_CHIPSET_ID, &value);
+       if (ret) {
+               nouveau_device_close((void *)&nvdev);
+               return ret;
+       }
+       nvdev->base.chipset = value;
+
+       ret = nouveau_device_get_param(&nvdev->base,
+                                      NOUVEAU_GETPARAM_HAS_BO_USAGE, &value);
+       if (!ret)
+               nvdev->has_bo_usage = value;
+
+       *dev = &nvdev->base;
+       return 0;
+}
+
+int
+nouveau_device_open(struct nouveau_device **dev, const char *busid)
+{
+       drm_context_t ctx;
+       int fd, ret;
+
+       if (!dev || *dev)
+               return -EINVAL;
+
+       fd = drmOpen("nouveau", busid);
+       if (fd < 0)
+               return -EINVAL;
+
+       ret = drmCreateContext(fd, &ctx);
+       if (ret) {
+               drmClose(fd);
+               return ret;
+       }
+
+       ret = nouveau_device_open_existing(dev, 1, fd, ctx);
+       if (ret) {
+           drmDestroyContext(fd, ctx);
+           drmClose(fd);
+           return ret;
+       }
+
+       return 0;
+}
+
+void
+nouveau_device_close(struct nouveau_device **dev)
+{
+       struct nouveau_device_priv *nvdev;
+
+       if (!dev || !*dev)
+               return;
+       nvdev = nouveau_device(*dev);
+       *dev = NULL;
+
+       nouveau_bo_takedown(&nvdev->base);
+
+       if (nvdev->needs_close) {
+               drmDestroyContext(nvdev->fd, nvdev->ctx);
+               drmClose(nvdev->fd);
+       }
+       free(nvdev);
+}
+
+int
+nouveau_device_get_param(struct nouveau_device *dev,
+                        uint64_t param, uint64_t *value)
+{
+       struct nouveau_device_priv *nvdev = nouveau_device(dev);
+       struct drm_nouveau_getparam g;
+       int ret;
+
+       if (!nvdev || !value)
+               return -EINVAL;
+
+       g.param = param;
+       ret = drmCommandWriteRead(nvdev->fd, DRM_NOUVEAU_GETPARAM,
+                                 &g, sizeof(g));
+       if (ret)
+               return ret;
+
+       *value = g.value;
+       return 0;
+}
+
+int
+nouveau_device_set_param(struct nouveau_device *dev,
+                        uint64_t param, uint64_t value)
+{
+       struct nouveau_device_priv *nvdev = nouveau_device(dev);
+       struct drm_nouveau_setparam s;
+       int ret;
+
+       if (!nvdev)
+               return -EINVAL;
+
+       s.param = param;
+       s.value = value;
+       ret = drmCommandWriteRead(nvdev->fd, DRM_NOUVEAU_SETPARAM,
+                                 &s, sizeof(s));
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
diff --git a/nouveau-1/nouveau_device.h b/nouveau-1/nouveau_device.h
new file mode 100644 (file)
index 0000000..c0d9333
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __NOUVEAU_DEVICE_H__
+#define __NOUVEAU_DEVICE_H__
+
+struct nouveau_device {
+       unsigned chipset;
+       uint64_t vm_vram_base;
+       uint64_t vm_vram_size;
+       uint64_t vm_gart_size;
+};
+
+#endif
diff --git a/nouveau-1/nouveau_drmif.h b/nouveau-1/nouveau_drmif.h
new file mode 100644 (file)
index 0000000..ec226a2
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2008 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __NOUVEAU_DRMIF_H__
+#define __NOUVEAU_DRMIF_H__
+
+#include <stdint.h>
+#include <xf86drm.h>
+
+#include "nouveau_device.h"
+
+struct nouveau_device_priv {
+       struct nouveau_device base;
+
+       int fd;
+       drm_context_t ctx;
+       drmLock *lock;
+       int needs_close;
+       int has_bo_usage;
+};
+#define nouveau_device(n) ((struct nouveau_device_priv *)(n))
+
+int
+nouveau_device_open_existing(struct nouveau_device **, int close,
+                            int fd, drm_context_t ctx);
+
+int
+nouveau_device_open(struct nouveau_device **, const char *busid);
+
+void
+nouveau_device_close(struct nouveau_device **);
+
+int
+nouveau_device_get_param(struct nouveau_device *, uint64_t param, uint64_t *v);
+
+int
+nouveau_device_set_param(struct nouveau_device *, uint64_t param, uint64_t val);
+
+#endif
diff --git a/nouveau-1/nouveau_grobj.c b/nouveau-1/nouveau_grobj.c
new file mode 100644 (file)
index 0000000..36344b9
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS 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.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+
+#include "nouveau_private.h"
+
+int
+nouveau_grobj_alloc(struct nouveau_channel *chan, uint32_t handle,
+                   int class, struct nouveau_grobj **grobj)
+{
+       struct nouveau_device_priv *nvdev = nouveau_device(chan->device);
+       struct nouveau_grobj_priv *nvgrobj;
+       struct drm_nouveau_grobj_alloc g;
+       int ret;
+
+       if (!nvdev || !grobj || *grobj)
+               return -EINVAL;
+
+       nvgrobj = calloc(1, sizeof(*nvgrobj));
+       if (!nvgrobj)
+               return -ENOMEM;
+       nvgrobj->base.channel = chan;
+       nvgrobj->base.handle  = handle;
+       nvgrobj->base.grclass = class;
+       nvgrobj->base.bound   = NOUVEAU_GROBJ_UNBOUND;
+       nvgrobj->base.subc    = -1;
+
+       g.channel = chan->id;
+       g.handle  = handle;
+       g.class   = class;
+       ret = drmCommandWrite(nvdev->fd, DRM_NOUVEAU_GROBJ_ALLOC,
+                             &g, sizeof(g));
+       if (ret) {
+               nouveau_grobj_free((void *)&nvgrobj);
+               return ret;
+       }
+
+       *grobj = &nvgrobj->base;
+       return 0;
+}
+
+int
+nouveau_grobj_ref(struct nouveau_channel *chan, uint32_t handle,
+                 struct nouveau_grobj **grobj)
+{
+       struct nouveau_grobj_priv *nvgrobj;
+
+       if (!chan || !grobj || *grobj)
+               return -EINVAL;
+
+       nvgrobj = calloc(1, sizeof(struct nouveau_grobj_priv));
+       if (!nvgrobj)
+               return -ENOMEM;
+       nvgrobj->base.channel = chan;
+       nvgrobj->base.handle = handle;
+       nvgrobj->base.grclass = 0;
+
+       *grobj = &nvgrobj->base;
+       return 0;
+}
+
+void
+nouveau_grobj_free(struct nouveau_grobj **grobj)
+{
+       struct nouveau_device_priv *nvdev;
+       struct nouveau_channel_priv *chan;
+       struct nouveau_grobj_priv *nvgrobj;
+
+       if (!grobj || !*grobj)
+               return;
+       nvgrobj = nouveau_grobj(*grobj);
+       *grobj = NULL;
+
+
+       chan = nouveau_channel(nvgrobj->base.channel);
+       nvdev = nouveau_device(chan->base.device);
+
+       if (nvgrobj->base.grclass) {
+               struct drm_nouveau_gpuobj_free f;
+
+               FIRE_RING(&chan->base);
+               f.channel = chan->drm.channel;
+               f.handle  = nvgrobj->base.handle;
+               drmCommandWrite(nvdev->fd, DRM_NOUVEAU_GPUOBJ_FREE,
+                               &f, sizeof(f)); 
+       }
+       if (nvgrobj->base.bound != NOUVEAU_GROBJ_UNBOUND)
+               chan->base.subc[nvgrobj->base.subc].gr = NULL;
+       free(nvgrobj);
+}
+
+void
+nouveau_grobj_autobind(struct nouveau_grobj *grobj)
+{
+       struct nouveau_channel *chan = grobj->channel;
+       struct nouveau_subchannel *subc = NULL;
+       int i;
+
+       for (i = 0; i < 8; i++) {
+               struct nouveau_subchannel *scc = &grobj->channel->subc[i];
+
+               if (scc->gr && scc->gr->bound == NOUVEAU_GROBJ_BOUND_EXPLICIT)
+                       continue;
+
+               if (!subc || scc->sequence < subc->sequence)
+                       subc = scc;
+       }
+
+       if (subc->gr) {
+               subc->gr->bound = NOUVEAU_GROBJ_UNBOUND;
+               subc->gr->subc  = -1;
+       }
+
+       subc->gr = grobj;
+       subc->gr->bound = NOUVEAU_GROBJ_BOUND;
+       subc->gr->subc  = subc - &grobj->channel->subc[0];
+
+       WAIT_RING(chan, 2);
+       if (chan->device->chipset < 0xc0) {
+               OUT_RING (chan, (1 << 18) | (grobj->subc << 13));
+               OUT_RING (chan, grobj->handle);
+       } else {
+               OUT_RING (chan, (2 << 28) | (1 << 16) | (grobj->subc << 13));
+               OUT_RING (chan, grobj->grclass);
+       }
+}
+
diff --git a/nouveau-1/nouveau_grobj.h b/nouveau-1/nouveau_grobj.h
new file mode 100644 (file)
index 0000000..51ac7d9
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __NOUVEAU_GROBJ_H__
+#define __NOUVEAU_GROBJ_H__
+
+#include "nouveau_channel.h"
+
+struct nouveau_grobj {
+       struct nouveau_channel *channel;
+       int grclass;
+       uint32_t handle;
+
+       enum {
+               NOUVEAU_GROBJ_UNBOUND = 0,
+               NOUVEAU_GROBJ_BOUND = 1,
+               NOUVEAU_GROBJ_BOUND_EXPLICIT = 2
+       } bound;
+       int subc;
+};
+
+int nouveau_grobj_alloc(struct nouveau_channel *, uint32_t handle,
+                              int class, struct nouveau_grobj **);
+int nouveau_grobj_ref(struct nouveau_channel *, uint32_t handle,
+                            struct nouveau_grobj **);
+void nouveau_grobj_free(struct nouveau_grobj **);
+void nouveau_grobj_autobind(struct nouveau_grobj *);
+
+#endif
diff --git a/nouveau-1/nouveau_notifier.c b/nouveau-1/nouveau_notifier.c
new file mode 100644 (file)
index 0000000..513fa63
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS 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.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/time.h>
+
+#include "nouveau_private.h"
+
+#define NOTIFIER(__v)                                                          \
+       struct nouveau_notifier_priv *nvnotify = nouveau_notifier(notifier);   \
+       volatile uint32_t *__v = (uint32_t *)((char *)nvnotify->map + (id * 32))
+
+int
+nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
+                      int count, struct nouveau_notifier **notifier)
+{
+       struct nouveau_notifier_priv *nvnotify;
+       int ret;
+
+       if (!chan || !notifier || *notifier)
+               return -EINVAL;
+
+       nvnotify = calloc(1, sizeof(struct nouveau_notifier_priv));
+       if (!nvnotify)
+               return -ENOMEM;
+       nvnotify->base.channel = chan;
+       nvnotify->base.handle  = handle;
+
+       nvnotify->drm.channel = chan->id;
+       nvnotify->drm.handle  = handle;
+       nvnotify->drm.size    = (count * 32);
+       if ((ret = drmCommandWriteRead(nouveau_device(chan->device)->fd,
+                                      DRM_NOUVEAU_NOTIFIEROBJ_ALLOC,
+                                      &nvnotify->drm,
+                                      sizeof(nvnotify->drm)))) {
+               nouveau_notifier_free((void *)&nvnotify);
+               return ret;
+       }
+
+       nvnotify->map = (char *)nouveau_channel(chan)->notifier_bo->map +
+                               nvnotify->drm.offset;
+       *notifier = &nvnotify->base;
+       return 0;
+}
+
+void
+nouveau_notifier_free(struct nouveau_notifier **notifier)
+{
+
+       struct nouveau_notifier_priv *nvnotify;
+       struct nouveau_channel_priv *nvchan;
+       struct nouveau_device_priv *nvdev;
+       struct drm_nouveau_gpuobj_free f;
+
+       if (!notifier || !*notifier)
+               return;
+       nvnotify = nouveau_notifier(*notifier);
+       *notifier = NULL;
+
+       nvchan = nouveau_channel(nvnotify->base.channel);
+       nvdev   = nouveau_device(nvchan->base.device);
+
+       FIRE_RING(&nvchan->base);
+
+       f.channel = nvchan->drm.channel;
+       f.handle  = nvnotify->base.handle;
+       drmCommandWrite(nvdev->fd, DRM_NOUVEAU_GPUOBJ_FREE, &f, sizeof(f));             
+       free(nvnotify);
+}
+
+void
+nouveau_notifier_reset(struct nouveau_notifier *notifier, int id)
+{
+       NOTIFIER(n);
+
+       n[NV_NOTIFY_TIME_0      /4] = 0x00000000;
+       n[NV_NOTIFY_TIME_1      /4] = 0x00000000;
+       n[NV_NOTIFY_RETURN_VALUE/4] = 0x00000000;
+       n[NV_NOTIFY_STATE       /4] = (NV_NOTIFY_STATE_STATUS_IN_PROCESS <<
+                                      NV_NOTIFY_STATE_STATUS_SHIFT);
+}
+
+uint32_t
+nouveau_notifier_status(struct nouveau_notifier *notifier, int id)
+{
+       NOTIFIER(n);
+
+       return n[NV_NOTIFY_STATE/4] >> NV_NOTIFY_STATE_STATUS_SHIFT;
+}
+
+uint32_t
+nouveau_notifier_return_val(struct nouveau_notifier *notifier, int id)
+{
+       NOTIFIER(n);
+
+       return n[NV_NOTIFY_RETURN_VALUE/4];
+}
+
+static inline double
+gettime(void)
+{
+       struct timeval tv;
+
+       gettimeofday(&tv, NULL);
+       return (double)tv.tv_sec + tv.tv_usec / 1000000.0;
+}
+
+int
+nouveau_notifier_wait_status(struct nouveau_notifier *notifier, int id,
+                            uint32_t status, double timeout)
+{
+       NOTIFIER(n);
+       double time = 0, t_start = gettime();
+
+       while (time <= timeout) {
+               uint32_t v;
+
+               v = n[NV_NOTIFY_STATE/4] >> NV_NOTIFY_STATE_STATUS_SHIFT;
+               if (v == status)
+                       return 0;
+
+               if (timeout)
+                       time = gettime() - t_start;
+       }
+
+       return -EBUSY;
+}
+
diff --git a/nouveau-1/nouveau_notifier.h b/nouveau-1/nouveau_notifier.h
new file mode 100644 (file)
index 0000000..dbc6a3b
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __NOUVEAU_NOTIFIER_H__
+#define __NOUVEAU_NOTIFIER_H__
+
+#define NV_NOTIFIER_SIZE                                                      32
+#define NV_NOTIFY_TIME_0                                              0x00000000
+#define NV_NOTIFY_TIME_1                                              0x00000004
+#define NV_NOTIFY_RETURN_VALUE                                        0x00000008
+#define NV_NOTIFY_STATE                                               0x0000000C
+#define NV_NOTIFY_STATE_STATUS_MASK                                   0xFF000000
+#define NV_NOTIFY_STATE_STATUS_SHIFT                                          24
+#define NV_NOTIFY_STATE_STATUS_COMPLETED                                    0x00
+#define NV_NOTIFY_STATE_STATUS_IN_PROCESS                                   0x01
+#define NV_NOTIFY_STATE_ERROR_CODE_MASK                               0x0000FFFF
+#define NV_NOTIFY_STATE_ERROR_CODE_SHIFT                                       0
+
+struct nouveau_notifier {
+       struct nouveau_channel *channel;
+       uint32_t handle;
+};
+
+int
+nouveau_notifier_alloc(struct nouveau_channel *, uint32_t handle, int count,
+                      struct nouveau_notifier **);
+
+void
+nouveau_notifier_free(struct nouveau_notifier **);
+
+void
+nouveau_notifier_reset(struct nouveau_notifier *, int id);
+
+uint32_t
+nouveau_notifier_status(struct nouveau_notifier *, int id);
+
+uint32_t
+nouveau_notifier_return_val(struct nouveau_notifier *, int id);
+
+int
+nouveau_notifier_wait_status(struct nouveau_notifier *, int id, uint32_t status,
+                            double timeout);
+
+#endif
diff --git a/nouveau-1/nouveau_private.h b/nouveau-1/nouveau_private.h
new file mode 100644 (file)
index 0000000..124fe87
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __NOUVEAU_PRIVATE_H__
+#define __NOUVEAU_PRIVATE_H__
+
+#include <stdint.h>
+#include <xf86drm.h>
+#include <nouveau_drm.h>
+
+#include "nouveau_drmif.h"
+#include "nouveau_device.h"
+#include "nouveau_channel.h"
+#include "nouveau_grobj.h"
+#include "nouveau_notifier.h"
+#include "nouveau_bo.h"
+#include "nouveau_resource.h"
+#include "nouveau_pushbuf.h"
+#include "nouveau_reloc.h"
+
+#define CALPB_BUFFERS 3
+
+struct nouveau_pushbuf_priv {
+       uint32_t cal_suffix0;
+       uint32_t cal_suffix1;
+       struct nouveau_bo *buffer[CALPB_BUFFERS];
+       int current;
+       int current_offset;
+
+       unsigned *pushbuf;
+       unsigned size;
+
+       uint32_t *marker;
+       unsigned marker_offset;
+       unsigned marker_relocs;
+       unsigned marker_push;
+
+       struct drm_nouveau_gem_pushbuf_bo *buffers;
+       unsigned nr_buffers;
+       struct drm_nouveau_gem_pushbuf_reloc *relocs;
+       unsigned nr_relocs;
+       struct drm_nouveau_gem_pushbuf_push push[NOUVEAU_GEM_MAX_PUSH];
+       unsigned nr_push;
+};
+#define nouveau_pushbuf(n) ((struct nouveau_pushbuf_priv *)(n))
+
+int
+nouveau_pushbuf_init(struct nouveau_channel *, int buf_size);
+void
+nouveau_pushbuf_fini(struct nouveau_channel *);
+
+struct nouveau_channel_priv {
+       struct nouveau_channel base;
+
+       struct drm_nouveau_channel_alloc drm;
+
+       struct nouveau_bo *notifier_bo;
+
+       struct nouveau_pushbuf_priv pb;
+};
+#define nouveau_channel(n) ((struct nouveau_channel_priv *)(n))
+
+struct nouveau_grobj_priv {
+       struct nouveau_grobj base;
+};
+#define nouveau_grobj(n) ((struct nouveau_grobj_priv *)(n))
+
+struct nouveau_notifier_priv {
+       struct nouveau_notifier base;
+
+       struct drm_nouveau_notifierobj_alloc drm;
+       volatile void *map;
+};
+#define nouveau_notifier(n) ((struct nouveau_notifier_priv *)(n))
+
+struct nouveau_bo_priv {
+       struct nouveau_bo base;
+       int refcount;
+
+       /* Buffer configuration + usage hints */
+       unsigned flags;
+       unsigned size;
+       unsigned align;
+       int user;
+
+       /* Tracking */
+       struct drm_nouveau_gem_pushbuf_bo *pending;
+       struct nouveau_channel *pending_channel;
+       int pending_refcnt;
+       int write_marker;
+
+       /* Userspace object */
+       void *sysmem;
+
+       /* Kernel object */
+       uint32_t global_handle;
+       drm_handle_t handle;
+       uint64_t map_handle;
+       int map_refcnt;
+       void *map;
+
+       /* Last known information from kernel on buffer status */
+       uint64_t offset;
+       uint32_t domain;
+};
+#define nouveau_bo(n) ((struct nouveau_bo_priv *)(n))
+
+int
+nouveau_bo_init(struct nouveau_device *);
+
+void
+nouveau_bo_takedown(struct nouveau_device *);
+
+struct drm_nouveau_gem_pushbuf_bo *
+nouveau_bo_emit_buffer(struct nouveau_channel *, struct nouveau_bo *);
+
+#endif
diff --git a/nouveau-1/nouveau_pushbuf.c b/nouveau-1/nouveau_pushbuf.c
new file mode 100644 (file)
index 0000000..59f60d9
--- /dev/null
@@ -0,0 +1,344 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "nouveau_private.h"
+
+#define PB_BUFMGR_DWORDS   (4096 / 2)
+#define PB_MIN_USER_DWORDS  2048
+
+static int
+nouveau_pushbuf_space(struct nouveau_channel *chan, unsigned min)
+{
+       struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
+       struct nouveau_pushbuf_priv *nvpb = &nvchan->pb;
+       struct nouveau_bo *bo;
+       int ret;
+
+       if (min < PB_MIN_USER_DWORDS)
+               min = PB_MIN_USER_DWORDS;
+
+       nvpb->current_offset = chan->cur - nvpb->pushbuf;
+       if (chan->cur + min + 2 <= chan->end)
+               return 0;
+
+       nvpb->current++;
+       if (nvpb->current == CALPB_BUFFERS)
+               nvpb->current = 0;
+       bo = nvpb->buffer[nvpb->current];
+
+       ret = nouveau_bo_map(bo, NOUVEAU_BO_WR);
+       if (ret)
+               return ret;
+
+       nvpb->size = (bo->size - 8) / 4;
+       nvpb->pushbuf = bo->map;
+       nvpb->current_offset = 0;
+
+       chan->cur = nvpb->pushbuf;
+       chan->end = nvpb->pushbuf + nvpb->size;
+
+       nouveau_bo_unmap(bo);
+       return 0;
+}
+
+static void
+nouveau_pushbuf_fini_call(struct nouveau_channel *chan)
+{
+       struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
+       struct nouveau_pushbuf_priv *nvpb = &nvchan->pb;
+       int i;
+
+       for (i = 0; i < CALPB_BUFFERS; i++)
+               nouveau_bo_ref(NULL, &nvpb->buffer[i]);
+       nvpb->pushbuf = NULL;
+}
+
+static int
+nouveau_pushbuf_init_call(struct nouveau_channel *chan, int buf_size)
+{
+       struct drm_nouveau_gem_pushbuf req;
+       struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
+       struct nouveau_pushbuf_priv *nvpb = &nvchan->pb;
+       struct nouveau_device *dev = chan->device;
+       uint32_t flags = 0;
+       int i, ret;
+
+       if (nvchan->drm.pushbuf_domains & NOUVEAU_GEM_DOMAIN_GART)
+               flags |= NOUVEAU_BO_GART;
+       else
+               flags |= NOUVEAU_BO_VRAM;
+
+       req.channel = chan->id;
+       req.nr_push = 0;
+       ret = drmCommandWriteRead(nouveau_device(dev)->fd,
+                                 DRM_NOUVEAU_GEM_PUSHBUF, &req, sizeof(req));
+       if (ret)
+               return ret;
+
+       for (i = 0; i < CALPB_BUFFERS; i++) {
+               ret = nouveau_bo_new(dev, flags | NOUVEAU_BO_MAP,
+                                    0, buf_size, &nvpb->buffer[i]);
+               if (ret) {
+                       nouveau_pushbuf_fini_call(chan);
+                       return ret;
+               }
+       }
+
+       nvpb->cal_suffix0 = req.suffix0;
+       nvpb->cal_suffix1 = req.suffix1;
+       return 0;
+}
+
+int
+nouveau_pushbuf_init(struct nouveau_channel *chan, int buf_size)
+{
+       struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
+       struct nouveau_pushbuf_priv *nvpb = &nvchan->pb;
+       int ret;
+
+       ret = nouveau_pushbuf_init_call(chan, buf_size);
+       if (ret)
+               return ret;
+
+       ret = nouveau_pushbuf_space(chan, 0);
+       if (ret)
+               return ret;
+
+       nvpb->buffers = calloc(NOUVEAU_GEM_MAX_BUFFERS,
+                              sizeof(struct drm_nouveau_gem_pushbuf_bo));
+       nvpb->relocs = calloc(NOUVEAU_GEM_MAX_RELOCS,
+                             sizeof(struct drm_nouveau_gem_pushbuf_reloc));
+       return 0;
+}
+
+void
+nouveau_pushbuf_fini(struct nouveau_channel *chan)
+{
+       struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
+       struct nouveau_pushbuf_priv *nvpb = &nvchan->pb;
+       nouveau_pushbuf_fini_call(chan);
+       free(nvpb->buffers);
+       free(nvpb->relocs);
+}
+
+static int
+nouveau_pushbuf_bo_add(struct nouveau_channel *chan, struct nouveau_bo *bo,
+                      unsigned offset, unsigned length)
+{
+       struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
+       struct nouveau_pushbuf_priv *nvpb = &nvchan->pb;
+       struct drm_nouveau_gem_pushbuf_push *p = &nvpb->push[nvpb->nr_push++];
+       struct drm_nouveau_gem_pushbuf_bo *pbbo;
+       struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
+
+       pbbo = nouveau_bo_emit_buffer(chan, bo);
+       if (!pbbo)
+               return -ENOMEM;
+       pbbo->valid_domains &= nvchan->drm.pushbuf_domains;
+       pbbo->read_domains |= nvchan->drm.pushbuf_domains;
+       nvbo->pending_refcnt++;
+
+       p->bo_index = pbbo - nvpb->buffers;
+       p->offset = offset;
+       p->length = length;
+       return 0;
+}
+
+int
+nouveau_pushbuf_submit(struct nouveau_channel *chan, struct nouveau_bo *bo,
+                      unsigned offset, unsigned length)
+{
+       struct nouveau_pushbuf_priv *nvpb = &nouveau_channel(chan)->pb;
+       int ret, len;
+
+       if ((AVAIL_RING(chan) + nvpb->current_offset) != nvpb->size) {
+               if (nvpb->cal_suffix0 || nvpb->cal_suffix1) {
+                       *(chan->cur++) = nvpb->cal_suffix0;
+                       *(chan->cur++) = nvpb->cal_suffix1;
+               }
+
+               len = (chan->cur - nvpb->pushbuf) - nvpb->current_offset;
+
+               ret = nouveau_pushbuf_bo_add(chan, nvpb->buffer[nvpb->current],
+                                            nvpb->current_offset * 4, len * 4);
+               if (ret)
+                       return ret;
+
+               nvpb->current_offset += len;
+       }
+
+       return bo ? nouveau_pushbuf_bo_add(chan, bo, offset, length) : 0;
+}
+
+static void
+nouveau_pushbuf_bo_unref(struct nouveau_pushbuf_priv *nvpb, int index)
+{
+       struct drm_nouveau_gem_pushbuf_bo *pbbo = &nvpb->buffers[index];
+       struct nouveau_bo *bo = (void *)(unsigned long)pbbo->user_priv;
+       struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
+
+       if (--nvbo->pending_refcnt)
+               return;
+
+       if (pbbo->presumed.valid == 0) {
+               nvbo->domain = pbbo->presumed.domain;
+               nvbo->offset = pbbo->presumed.offset;
+       }
+
+       nvbo->pending = NULL;
+       nouveau_bo_ref(NULL, &bo);
+
+       /* we only ever remove from the tail of the pending lists,
+        * so this is safe.
+        */
+       nvpb->nr_buffers--;
+}
+
+int
+nouveau_pushbuf_flush(struct nouveau_channel *chan, unsigned min)
+{
+       struct nouveau_device_priv *nvdev = nouveau_device(chan->device);
+       struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
+       struct nouveau_pushbuf_priv *nvpb = &nvchan->pb;
+       struct drm_nouveau_gem_pushbuf req;
+       unsigned i;
+       int ret;
+
+       ret = nouveau_pushbuf_submit(chan, NULL, 0, 0);
+       if (ret)
+               return ret;
+
+       if (!nvpb->nr_push)
+               return 0;
+
+       req.channel = chan->id;
+       req.nr_push = nvpb->nr_push;
+       req.push = (uint64_t)(unsigned long)nvpb->push;
+       req.nr_buffers = nvpb->nr_buffers;
+       req.buffers = (uint64_t)(unsigned long)nvpb->buffers;
+       req.nr_relocs = nvpb->nr_relocs;
+       req.relocs = (uint64_t)(unsigned long)nvpb->relocs;
+       req.suffix0 = nvpb->cal_suffix0;
+       req.suffix1 = nvpb->cal_suffix1;
+
+       do {
+               ret = drmCommandWriteRead(nvdev->fd, DRM_NOUVEAU_GEM_PUSHBUF,
+                                         &req, sizeof(req));
+       } while (ret == -EAGAIN);
+       nvpb->cal_suffix0 = req.suffix0;
+       nvpb->cal_suffix1 = req.suffix1;
+       nvdev->base.vm_vram_size = req.vram_available;
+       nvdev->base.vm_gart_size = req.gart_available;
+
+       /* Update presumed offset/domain for any buffers that moved.
+        * Dereference all buffers on validate list
+        */
+       for (i = 0; i < nvpb->nr_relocs; i++) {
+               nouveau_pushbuf_bo_unref(nvpb, nvpb->relocs[i].bo_index);
+               nouveau_pushbuf_bo_unref(nvpb, nvpb->relocs[i].reloc_bo_index);
+       }
+
+       for (i = 0; i < nvpb->nr_push; i++)
+               nouveau_pushbuf_bo_unref(nvpb, nvpb->push[i].bo_index);
+
+       nvpb->nr_buffers = 0;
+       nvpb->nr_relocs = 0;
+       nvpb->nr_push = 0;
+
+       /* Allocate space for next push buffer */
+       if (nouveau_pushbuf_space(chan, min))
+               assert(0);
+
+       if (chan->flush_notify)
+               chan->flush_notify(chan);
+
+       nvpb->marker = NULL;
+       return ret;
+}
+
+int
+nouveau_pushbuf_marker_emit(struct nouveau_channel *chan,
+                           unsigned wait_dwords, unsigned wait_relocs)
+{
+       struct nouveau_pushbuf_priv *nvpb = &nouveau_channel(chan)->pb;
+
+       if (AVAIL_RING(chan) < wait_dwords)
+               return nouveau_pushbuf_flush(chan, wait_dwords);
+
+       if (nvpb->nr_relocs + wait_relocs >= NOUVEAU_GEM_MAX_RELOCS)
+               return nouveau_pushbuf_flush(chan, wait_dwords);
+
+       nvpb->marker = chan->cur;
+       nvpb->marker_offset = nvpb->current_offset;
+       nvpb->marker_push = nvpb->nr_push;
+       nvpb->marker_relocs = nvpb->nr_relocs;
+       return 0;
+}
+
+void
+nouveau_pushbuf_marker_undo(struct nouveau_channel *chan)
+{
+       struct nouveau_pushbuf_priv *nvpb = &nouveau_channel(chan)->pb;
+       unsigned i;
+
+       if (!nvpb->marker)
+               return;
+
+       /* undo any relocs/buffers added to the list since last marker */
+       for (i = nvpb->marker_relocs; i < nvpb->nr_relocs; i++) {
+               nouveau_pushbuf_bo_unref(nvpb, nvpb->relocs[i].bo_index);
+               nouveau_pushbuf_bo_unref(nvpb, nvpb->relocs[i].reloc_bo_index);
+       }
+       nvpb->nr_relocs = nvpb->marker_relocs;
+
+       for (i = nvpb->marker_push; i < nvpb->nr_push; i++)
+               nouveau_pushbuf_bo_unref(nvpb, nvpb->push[i].bo_index);
+       nvpb->nr_push = nvpb->marker_push;
+
+       /* reset pushbuf back to last marker */
+       chan->cur = nvpb->marker;
+       nvpb->current_offset = nvpb->marker_offset;
+       nvpb->marker = NULL;
+}
+
+int
+nouveau_pushbuf_emit_reloc(struct nouveau_channel *chan, void *ptr,
+                          struct nouveau_bo *bo, uint32_t data, uint32_t data2,
+                          uint32_t flags, uint32_t vor, uint32_t tor)
+{
+       struct nouveau_pushbuf_priv *nvpb = &nouveau_channel(chan)->pb;
+       int ret;
+
+       ret = nouveau_reloc_emit(chan, nvpb->buffer[nvpb->current],
+                                (char *)ptr - (char *)nvpb->pushbuf, ptr,
+                                bo, data, data2, flags, vor, tor);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
diff --git a/nouveau-1/nouveau_pushbuf.h b/nouveau-1/nouveau_pushbuf.h
new file mode 100644 (file)
index 0000000..2a98789
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __NOUVEAU_PUSHBUF_H__
+#define __NOUVEAU_PUSHBUF_H__
+
+#include <assert.h>
+#include <string.h>
+
+#include "nouveau_bo.h"
+#include "nouveau_grobj.h"
+
+int
+nouveau_pushbuf_flush(struct nouveau_channel *, unsigned min);
+
+int
+nouveau_pushbuf_marker_emit(struct nouveau_channel *chan,
+                           unsigned wait_dwords, unsigned wait_relocs);
+
+void
+nouveau_pushbuf_marker_undo(struct nouveau_channel *chan);
+
+int
+nouveau_pushbuf_emit_reloc(struct nouveau_channel *, void *ptr,
+                          struct nouveau_bo *, uint32_t data, uint32_t data2,
+                          uint32_t flags, uint32_t vor, uint32_t tor);
+
+int
+nouveau_pushbuf_submit(struct nouveau_channel *chan, struct nouveau_bo *bo,
+                      unsigned offset, unsigned length);
+
+/* Push buffer access macros */
+static __inline__ int
+MARK_RING(struct nouveau_channel *chan, unsigned dwords, unsigned relocs)
+{
+       return nouveau_pushbuf_marker_emit(chan, dwords, relocs);
+}
+
+static __inline__ void
+MARK_UNDO(struct nouveau_channel *chan)
+{
+       nouveau_pushbuf_marker_undo(chan);
+}
+
+static __inline__ void
+OUT_RING(struct nouveau_channel *chan, unsigned data)
+{
+       *(chan->cur++) = (data);
+}
+
+static __inline__ void
+OUT_RINGp(struct nouveau_channel *chan, const void *data, unsigned size)
+{
+       memcpy(chan->cur, data, size * 4);
+       chan->cur += size;
+}
+
+static __inline__ void
+OUT_RINGf(struct nouveau_channel *chan, float f)
+{
+       union { uint32_t i; float f; } c;
+       c.f = f;
+       OUT_RING(chan, c.i);
+}
+
+static __inline__ unsigned
+AVAIL_RING(struct nouveau_channel *chan)
+{
+       return chan->end - chan->cur;
+}
+
+static __inline__ void
+WAIT_RING(struct nouveau_channel *chan, unsigned size)
+{
+       if (chan->cur + size > chan->end)
+               nouveau_pushbuf_flush(chan, size);
+}
+
+static __inline__ void
+FIRE_RING(struct nouveau_channel *chan)
+{
+       nouveau_pushbuf_flush(chan, 0);
+}
+
+static __inline__ int
+OUT_RELOC(struct nouveau_channel *chan, struct nouveau_bo *bo,
+         unsigned data, unsigned flags, unsigned vor, unsigned tor)
+{
+       return nouveau_pushbuf_emit_reloc(chan, chan->cur++, bo,
+                                         data, 0, flags, vor, tor);
+}
+
+static __inline__ int
+OUT_RELOC2(struct nouveau_channel *chan, struct nouveau_bo *bo,
+          unsigned data, unsigned data2, unsigned flags,
+          unsigned vor, unsigned tor)
+{
+       return nouveau_pushbuf_emit_reloc(chan, chan->cur++, bo,
+                                         data, data2, flags, vor, tor);
+}
+
+/* Raw data + flags depending on FB/TT buffer */
+static __inline__ int
+OUT_RELOCd(struct nouveau_channel *chan, struct nouveau_bo *bo,
+          unsigned data, unsigned flags, unsigned vor, unsigned tor)
+{
+       return OUT_RELOC(chan, bo, data, flags | NOUVEAU_BO_OR, vor, tor);
+}
+
+/* FB/TT object handle */
+static __inline__ int
+OUT_RELOCo(struct nouveau_channel *chan, struct nouveau_bo *bo,
+          unsigned flags)
+{
+       return OUT_RELOC(chan, bo, 0, flags | NOUVEAU_BO_OR,
+                        chan->vram->handle, chan->gart->handle);
+}
+
+/* Low 32-bits of offset */
+static __inline__ int
+OUT_RELOCl(struct nouveau_channel *chan, struct nouveau_bo *bo,
+          unsigned delta, unsigned flags)
+{
+       return OUT_RELOC(chan, bo, delta, flags | NOUVEAU_BO_LOW, 0, 0);
+}
+
+/* Low 32-bits of offset + GPU linear access range info */
+static __inline__ int
+OUT_RELOCr(struct nouveau_channel *chan, struct nouveau_bo *bo,
+          unsigned delta, unsigned size, unsigned flags)
+{
+       return OUT_RELOC2(chan, bo, delta, size, flags | NOUVEAU_BO_LOW, 0, 0);
+}
+
+/* High 32-bits of offset */
+static __inline__ int
+OUT_RELOCh(struct nouveau_channel *chan, struct nouveau_bo *bo,
+          unsigned delta, unsigned flags)
+{
+       return OUT_RELOC(chan, bo, delta, flags | NOUVEAU_BO_HIGH, 0, 0);
+}
+
+#endif
diff --git a/nouveau-1/nouveau_reloc.c b/nouveau-1/nouveau_reloc.c
new file mode 100644 (file)
index 0000000..cd219db
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2010 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "nouveau_private.h"
+
+static uint32_t
+nouveau_reloc_calc(struct drm_nouveau_gem_pushbuf_bo *pbbo,
+                  struct drm_nouveau_gem_pushbuf_reloc *r)
+{
+       uint32_t push = 0;
+
+       if (r->flags & NOUVEAU_GEM_RELOC_LOW)
+               push = (pbbo->presumed.offset + r->data);
+       else
+       if (r->flags & NOUVEAU_GEM_RELOC_HIGH)
+               push = (pbbo->presumed.offset + r->data) >> 32;
+       else
+               push = r->data;
+
+       if (r->flags & NOUVEAU_GEM_RELOC_OR) {
+               if (pbbo->presumed.domain & NOUVEAU_GEM_DOMAIN_VRAM)
+                       push |= r->vor;
+               else
+                       push |= r->tor;
+       }
+
+       return push;
+}
+
+int
+nouveau_reloc_emit(struct nouveau_channel *chan, struct nouveau_bo *reloc_bo,
+                  uint32_t reloc_offset, uint32_t *reloc_ptr,
+                  struct nouveau_bo *bo, uint32_t data, uint32_t data2,
+                  uint32_t flags, uint32_t vor, uint32_t tor)
+{
+       struct nouveau_pushbuf_priv *nvpb = &nouveau_channel(chan)->pb;
+       struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
+       struct drm_nouveau_gem_pushbuf_reloc *r;
+       struct drm_nouveau_gem_pushbuf_bo *pbbo, *rpbbo;
+       uint32_t domains = 0;
+
+       if (nvpb->nr_relocs >= NOUVEAU_GEM_MAX_RELOCS) {
+               fprintf(stderr, "too many relocs!!\n");
+               return -ENOMEM;
+       }
+
+       if (nvbo->user && (flags & NOUVEAU_BO_WR)) {
+               fprintf(stderr, "write to user buffer!!\n");
+               return -EINVAL;
+       }
+
+       /* We're about to reloc a user buffer, better make sure we don't cause
+        * a double migration.
+        */
+       if (!(nvbo->flags & (NOUVEAU_BO_GART | NOUVEAU_BO_VRAM)))
+               nvbo->flags |= (flags & (NOUVEAU_BO_GART | NOUVEAU_BO_VRAM));
+
+       /* add buffer to validation list */
+       pbbo = nouveau_bo_emit_buffer(chan, bo);
+       if (!pbbo) {
+               fprintf(stderr, "buffer emit fail :(\n");
+               return -ENOMEM;
+       }
+       nouveau_bo(bo)->pending_refcnt++;
+
+       if (flags & (NOUVEAU_BO_VRAM | NOUVEAU_BO_GART)) {
+               if (flags & NOUVEAU_BO_VRAM)
+                       domains |= NOUVEAU_GEM_DOMAIN_VRAM;
+               if (flags & NOUVEAU_BO_GART)
+                       domains |= NOUVEAU_GEM_DOMAIN_GART;
+       } else
+               domains |= nvbo->domain;
+
+       if (!(pbbo->valid_domains & domains)) {
+               fprintf(stderr, "no valid domains remain!\n");
+               return -EINVAL;
+       }
+       pbbo->valid_domains &= domains;
+
+       assert(flags & NOUVEAU_BO_RDWR);
+       if (flags & NOUVEAU_BO_RD) {
+               pbbo->read_domains |= domains;
+       }
+       if (flags & NOUVEAU_BO_WR) {
+               pbbo->write_domains |= domains;
+               nvbo->write_marker = 1;
+       }
+
+       /* nvc0 gallium driver uses reloc_emit() with NULL target buffer
+        * to inform bufmgr of a buffer's use - however, we need something
+        * to track, so create a reloc for now, and hope it never triggers
+        * (it shouldn't, constant virtual address..)..
+        */
+       if (!reloc_bo) {
+               reloc_bo  = nvpb->buffer[nvpb->current];
+               reloc_offset = 0;
+               reloc_ptr = NULL;
+       }
+
+       /* add reloc target bo to validation list, and create the reloc */
+       rpbbo = nouveau_bo_emit_buffer(chan, reloc_bo);
+       if (!rpbbo)
+               return -ENOMEM;
+       nouveau_bo(reloc_bo)->pending_refcnt++;
+
+       r = nvpb->relocs + nvpb->nr_relocs++;
+       r->reloc_bo_index = rpbbo - nvpb->buffers;
+       r->reloc_bo_offset = reloc_offset;
+       r->bo_index = pbbo - nvpb->buffers;
+       r->flags = 0;
+       if (flags & NOUVEAU_BO_LOW)
+               r->flags |= NOUVEAU_GEM_RELOC_LOW;
+       if (flags & NOUVEAU_BO_HIGH)
+               r->flags |= NOUVEAU_GEM_RELOC_HIGH;
+       if (flags & NOUVEAU_BO_OR)
+               r->flags |= NOUVEAU_GEM_RELOC_OR;
+       r->data = data;
+       r->vor = vor;
+       r->tor = tor;
+
+       if (reloc_ptr) {
+               if (flags & NOUVEAU_BO_DUMMY)
+                       *reloc_ptr = 0;
+               else
+                       *reloc_ptr = nouveau_reloc_calc(pbbo, r);
+       }
+
+       return 0;
+}
+
diff --git a/nouveau-1/nouveau_reloc.h b/nouveau-1/nouveau_reloc.h
new file mode 100644 (file)
index 0000000..24ddb52
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2010 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __NOUVEAU_RELOC_H__
+#define __NOUVEAU_RELOC_H__
+
+int
+nouveau_reloc_emit(struct nouveau_channel *chan, struct nouveau_bo *reloc_bo,
+                  uint32_t reloc_offset, uint32_t *reloc_ptr,
+                  struct nouveau_bo *bo, uint32_t data, uint32_t data2,
+                  uint32_t flags, uint32_t vor, uint32_t tor);
+
+#endif
diff --git a/nouveau-1/nouveau_resource.c b/nouveau-1/nouveau_resource.c
new file mode 100644 (file)
index 0000000..7acaf7d
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS 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.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+
+#include "nouveau_private.h"
+
+int
+nouveau_resource_init(struct nouveau_resource **heap,
+                     unsigned start, unsigned size)
+{
+       struct nouveau_resource *r;
+
+       r = calloc(1, sizeof(struct nouveau_resource));
+       if (!r)
+               return 1;
+
+       r->start = start;
+       r->size  = size;
+       *heap = r;
+       return 0;
+}
+
+void
+nouveau_resource_destroy(struct nouveau_resource **heap)
+{
+       if (!*heap)
+               return;
+       free(*heap);
+       *heap = NULL;
+}
+
+int
+nouveau_resource_alloc(struct nouveau_resource *heap, unsigned size, void *priv,
+                      struct nouveau_resource **res)
+{
+       struct nouveau_resource *r;
+
+       if (!heap || !size || !res || *res)
+               return 1;
+
+       while (heap) {
+               if (!heap->in_use && heap->size >= size) {
+                       r = calloc(1, sizeof(struct nouveau_resource));
+                       if (!r)
+                               return 1;
+
+                       r->start  = (heap->start + heap->size) - size;
+                       r->size   = size;
+                       r->in_use = 1;
+                       r->priv   = priv;
+
+                       heap->size -= size;
+
+                       r->next = heap->next;
+                       if (heap->next)
+                               heap->next->prev = r;
+                       r->prev = heap;
+                       heap->next = r;
+
+                       *res = r;
+                       return 0;
+               }
+                       
+               heap = heap->next;
+       }
+
+       return 1;
+}
+
+void
+nouveau_resource_free(struct nouveau_resource **res)
+{
+       struct nouveau_resource *r;
+
+       if (!res || !*res)
+               return;
+       r = *res;
+       *res = NULL;
+
+       r->in_use = 0;
+
+       if (r->next && !r->next->in_use) {
+               struct nouveau_resource *new = r->next;
+
+               new->prev = r->prev;
+               if (r->prev)
+                       r->prev->next = new;
+               new->size += r->size;
+               new->start = r->start;
+
+               free(r);
+               r = new;
+       }
+
+       if (r->prev && !r->prev->in_use) {
+               r->prev->next = r->next;
+               if (r->next)
+                       r->next->prev = r->prev;
+               r->prev->size += r->size;
+               free(r);
+       }
+       
+}
diff --git a/nouveau-1/nouveau_resource.h b/nouveau-1/nouveau_resource.h
new file mode 100644 (file)
index 0000000..b760dfb
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __NOUVEAU_RESOURCE_H__
+#define __NOUVEAU_RESOURCE_H__
+
+struct nouveau_resource {
+       struct nouveau_resource *prev;
+       struct nouveau_resource *next;
+
+       int in_use;
+       void *priv;
+
+       unsigned int start;
+       unsigned int size;
+};
+
+int
+nouveau_resource_init(struct nouveau_resource **heap, unsigned start,
+                     unsigned size);
+
+void
+nouveau_resource_destroy(struct nouveau_resource **heap);
+
+int
+nouveau_resource_alloc(struct nouveau_resource *heap, unsigned size, void *priv,
+                      struct nouveau_resource **);
+
+void
+nouveau_resource_free(struct nouveau_resource **);
+
+#endif
diff --git a/nouveau-1/nv04_pushbuf.h b/nouveau-1/nv04_pushbuf.h
new file mode 100644 (file)
index 0000000..586b284
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __NV04_PUSHBUF_H__
+#define __NV04_PUSHBUF_H__
+
+#include "nouveau_pushbuf.h"
+
+static __inline__ void
+BEGIN_RING(struct nouveau_channel *chan, struct nouveau_grobj *gr,
+          unsigned mthd, unsigned size)
+{
+       if (gr->bound == NOUVEAU_GROBJ_UNBOUND)
+               nouveau_grobj_autobind(gr);
+       chan->subc[gr->subc].sequence = chan->subc_sequence++;
+
+       WAIT_RING(chan, size + 1);
+       OUT_RING(chan, (gr->subc << 13) | (size << 18) | mthd);
+}
+
+/* non-incrementing BEGIN_RING */
+static __inline__ void
+BEGIN_RING_NI(struct nouveau_channel *chan, struct nouveau_grobj *gr,
+          unsigned mthd, unsigned size)
+{
+       BEGIN_RING(chan, gr, mthd | 0x40000000, size);
+}
+
+static __inline__ void
+BIND_RING(struct nouveau_channel *chan, struct nouveau_grobj *gr, unsigned sc)
+{
+       struct nouveau_subchannel *subc = &gr->channel->subc[sc];
+
+       if (subc->gr) {
+               if (subc->gr->bound == NOUVEAU_GROBJ_BOUND_EXPLICIT)
+                       assert(0);
+               subc->gr->bound = NOUVEAU_GROBJ_UNBOUND;
+       }
+       subc->gr = gr;
+       subc->gr->subc = sc;
+       subc->gr->bound = NOUVEAU_GROBJ_BOUND_EXPLICIT;
+
+       BEGIN_RING(chan, gr, 0x0000, 1);
+       OUT_RING  (chan, gr->handle);
+}
+
+#endif
diff --git a/nouveau-1/nvc0_pushbuf.h b/nouveau-1/nvc0_pushbuf.h
new file mode 100644 (file)
index 0000000..40dc7e6
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2010 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __NVC0_PUSHBUF_H__
+#define __NVC0_PUSHBUF_H__
+
+#include "nouveau_pushbuf.h"
+
+#define SUBC_BIND(chan, gr) do {                                               \
+       if (gr->bound == NOUVEAU_GROBJ_UNBOUND)                                \
+               nouveau_grobj_autobind(gr);                                    \
+       chan->subc[gr->subc].sequence = chan->subc_sequence++;                 \
+} while (0)
+
+/* incremental methods */
+static __inline__ void
+BEGIN_RING(struct nouveau_channel *chan, struct nouveau_grobj *gr,
+          unsigned mthd, unsigned size)
+{
+       SUBC_BIND(chan, gr);
+       WAIT_RING(chan, size + 1);
+       OUT_RING (chan, (0x2 << 28) | (size << 16) | (gr->subc << 13) | (mthd >> 2));
+}
+
+/* non-incremental */
+static __inline__ void
+BEGIN_RING_NI(struct nouveau_channel *chan, struct nouveau_grobj *gr,
+             unsigned mthd, unsigned size)
+{
+       SUBC_BIND(chan, gr);
+       WAIT_RING(chan, size + 1);
+       OUT_RING (chan, (0x6 << 28) | (size << 16) | (gr->subc << 13) | (mthd >> 2));
+}
+
+/* increment-once */
+static __inline__ void
+BEGIN_RING_1I(struct nouveau_channel *chan, struct nouveau_grobj *gr,
+             unsigned mthd, unsigned size)
+{
+       SUBC_BIND(chan, gr);
+       WAIT_RING(chan, size + 1);
+       OUT_RING (chan, (0xa << 28) | (size << 16) | (gr->subc << 13) | (mthd >> 2));
+}
+
+/* inline-data */
+static __inline__ void
+IMMED_RING(struct nouveau_channel *chan, struct nouveau_grobj *gr,
+          unsigned mthd, unsigned data)
+{
+       SUBC_BIND(chan, gr);
+       WAIT_RING(chan, 1);
+       OUT_RING (chan, (0x8 << 28) | (data << 16) | (gr->subc << 13) | (mthd >> 2));
+}
+
+static __inline__ void
+BIND_RING(struct nouveau_channel *chan, struct nouveau_grobj *gr, unsigned sc)
+{
+       struct nouveau_subchannel *subc = &gr->channel->subc[sc];
+
+       if (subc->gr) {
+               if (subc->gr->bound == NOUVEAU_GROBJ_BOUND_EXPLICIT)
+                       assert(0);
+               subc->gr->bound = NOUVEAU_GROBJ_UNBOUND;
+       }
+       subc->gr = gr;
+       subc->gr->subc = sc;
+       subc->gr->bound = NOUVEAU_GROBJ_BOUND_EXPLICIT;
+
+       BEGIN_RING(chan, gr, 0x0000, 1);
+       OUT_RING  (chan, gr->grclass);
+}
+
+#endif