libdrm/libdrm-2.4.37-nouveau-1.patch

2922 lines
81 KiB
Diff
Raw Permalink Normal View History

diff --git a/Makefile.am b/Makefile.am
index 256a8cc..045add1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -34,7 +34,7 @@ INTEL_SUBDIR = intel
endif
if HAVE_NOUVEAU
-NOUVEAU_SUBDIR = nouveau
+NOUVEAU_SUBDIR = nouveau-1 nouveau
endif
if HAVE_RADEON
diff --git a/configure.ac b/configure.ac
index a1c8c69..6439b81 100644
--- a/configure.ac
+++ b/configure.ac
@@ -319,6 +319,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
index 0000000..7e6aa13
--- /dev/null
+++ b/nouveau-1/Makefile.am
@@ -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
index 0000000..8f3d40f
--- /dev/null
+++ b/nouveau-1/libdrm_nouveau1.pc.in
@@ -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
index 0000000..d6bb22d
--- /dev/null
+++ b/nouveau-1/nouveau_bo.c
@@ -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
index 0000000..3a1f2d4
--- /dev/null
+++ b/nouveau-1/nouveau_bo.h
@@ -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
index 0000000..96fa03b
--- /dev/null
+++ b/nouveau-1/nouveau_channel.c
@@ -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
index 0000000..d61a4c0
--- /dev/null
+++ b/nouveau-1/nouveau_channel.h
@@ -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
index 0000000..425c5d2
--- /dev/null
+++ b/nouveau-1/nouveau_device.c
@@ -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
index 0000000..c0d9333
--- /dev/null
+++ b/nouveau-1/nouveau_device.h
@@ -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
index 0000000..ec226a2
--- /dev/null
+++ b/nouveau-1/nouveau_drmif.h
@@ -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
index 0000000..36344b9
--- /dev/null
+++ b/nouveau-1/nouveau_grobj.c
@@ -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
index 0000000..51ac7d9
--- /dev/null
+++ b/nouveau-1/nouveau_grobj.h
@@ -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
index 0000000..513fa63
--- /dev/null
+++ b/nouveau-1/nouveau_notifier.c
@@ -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
index 0000000..dbc6a3b
--- /dev/null
+++ b/nouveau-1/nouveau_notifier.h
@@ -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
index 0000000..124fe87
--- /dev/null
+++ b/nouveau-1/nouveau_private.h
@@ -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
index 0000000..59f60d9
--- /dev/null
+++ b/nouveau-1/nouveau_pushbuf.c
@@ -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
index 0000000..2a98789
--- /dev/null
+++ b/nouveau-1/nouveau_pushbuf.h
@@ -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
index 0000000..cd219db
--- /dev/null
+++ b/nouveau-1/nouveau_reloc.c
@@ -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
index 0000000..24ddb52
--- /dev/null
+++ b/nouveau-1/nouveau_reloc.h
@@ -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
index 0000000..7acaf7d
--- /dev/null
+++ b/nouveau-1/nouveau_resource.c
@@ -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
index 0000000..b760dfb
--- /dev/null
+++ b/nouveau-1/nouveau_resource.h
@@ -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
index 0000000..586b284
--- /dev/null
+++ b/nouveau-1/nv04_pushbuf.h
@@ -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
index 0000000..40dc7e6
--- /dev/null
+++ b/nouveau-1/nvc0_pushbuf.h
@@ -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