diff --git a/README.md b/README.md index e1a8d8a..dd5dd2e 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,4 @@ # libdrm +A library interface to Linux DRM (Direct Rendering Manager). + diff --git a/libdrm-2.4.37-nouveau-1.patch b/libdrm-2.4.37-nouveau-1.patch new file mode 100644 index 0000000..10f02a9 --- /dev/null +++ b/libdrm-2.4.37-nouveau-1.patch @@ -0,0 +1,2921 @@ +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 ++#endif ++#include ++#include ++#include ++#include ++ ++#include ++ ++#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 ++#include ++#include ++ ++#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 ++#include ++#include ++ ++#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 ++#include ++ ++#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 ++#include ++ ++#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 ++#include ++#include ++ ++#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 ++#include ++#include ++ ++#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 ++#include ++#include ++#include ++ ++#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 ++#include ++ ++#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 ++#include ++#include ++#include ++ ++#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 ++#include ++ ++#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 diff --git a/libdrm.spec b/libdrm.spec new file mode 100644 index 0000000..322346e --- /dev/null +++ b/libdrm.spec @@ -0,0 +1,245 @@ +Name: libdrm +Epoch: 1 +Version: 2.4.54 +Release: 1mamba +Summary: A library interface to Linux DRM (Direct Rendering Manager) +Group: System/Libraries +Vendor: openmamba +Distribution: openmamba +Packager: Silvan Calarco +URL: http://dri.freedesktop.org +Source: http://dri.freedesktop.org/libdrm/libdrm-%{version}.tar.bz2 +Patch0: %{name}-2.4.37-nouveau-1.patch +License: MIT +## AUTOBUILDREQ-BEGIN +BuildRequires: glibc-devel +BuildRequires: libpciaccess-devel +BuildRequires: libpthread-stubs-devel +BuildRequires: pkg-config +## AUTOBUILDREQ-END +BuildRoot: %{_tmppath}/%{name}-%{version}-root + +%description +A library interface to Linux DRM (Direct Rendering Manager). + +%package devel +Summary: Devel package for %{name} +Group: Development/Libraries +Requires: %{name} = %{?epoch:%epoch:}%{version}-%{release} + +%description devel +A library interface to Linux DRM (Direct Rendering Manager). +This package contains static libraries and header files need for development. + +%prep +%setup -q +#%patch0 -p1 + +%build +#autoreconf +%configure \ + --enable-udev \ + --enable-vmwgfx-experimental-api \ + --enable-omap-experimental-api \ + --enable-exynos-experimental-api \ + --enable-intel \ + --enable-radeon \ + --enable-nouveau + +%make + +%install +[ "%{buildroot}" != / ] && rm -rf "%{buildroot}" +%makeinstall + +%clean +[ "%{buildroot}" != / ] && rm -rf "%{buildroot}" + +%files +%defattr(-,root,root) +%{_libdir}/libdrm.so.* +%ifarch %{ix86} x86_64 +%{_libdir}/libdrm_intel.so.* +%endif +%{_libdir}/libdrm_nouveau.so.* +%{_libdir}/libdrm_radeon.so.* +%{_libdir}/libdrm_exynos.so.* +%{_libdir}/libdrm_omap.so.* +%{_libdir}/libkms.so.* +%doc README + +%files devel +%defattr(-,root,root) +%dir %{_includedir}/libdrm +%{_includedir}/libdrm/*.h +%dir %{_includedir}/libkms +%{_includedir}/libkms/libkms.h +%dir %{_includedir}/exynos +%{_includedir}/exynos/exynos_drm.h +#%dir %{_includedir}/nouveau +#%{_includedir}/nouveau/nouveau_*.h +#%{_includedir}/nouveau/nv*_pushbuf.h +%dir %{_includedir}/omap +%{_includedir}/omap/omap_drm.h +%{_includedir}/*.h +%{_libdir}/libdrm.la +%{_libdir}/libdrm.so +%ifarch %{ix86} x86_64 +%{_libdir}/libdrm_intel.la +%{_libdir}/libdrm_intel.so +%endif +%{_libdir}/libdrm_nouveau.la +%{_libdir}/libdrm_nouveau.so +%{_libdir}/libdrm_radeon.la +%{_libdir}/libdrm_radeon.so +%{_libdir}/libdrm_exynos.la +%{_libdir}/libdrm_exynos.so +%{_libdir}/libdrm_omap.la +%{_libdir}/libdrm_omap.so +%{_libdir}/libkms.la +%{_libdir}/libkms.so +%{_libdir}/pkgconfig/*.pc +%{_mandir}/man3/drmAvailable.3* +%{_mandir}/man3/drmHandleEvent.3* +%{_mandir}/man3/drmModeGetResources.3* +%{_mandir}/man7/drm-gem.7* +%{_mandir}/man7/drm-kms.7* +%{_mandir}/man7/drm-memory.7* +%{_mandir}/man7/drm-mm.7* +%{_mandir}/man7/drm-ttm.7* +%{_mandir}/man7/drm.7* + +%changelog +* Sat May 03 2014 Automatic Build System 2.4.54-1mamba +- automatic version update by autodist + +* Fri Apr 11 2014 Automatic Build System 2.4.53-1mamba +- automatic version update by autodist + +* Wed Jan 22 2014 Automatic Build System 2.4.52-1mamba +- automatic version update by autodist + +* Thu Jan 09 2014 Automatic Build System 2.4.51-1mamba +- automatic version update by autodist + +* Wed Dec 04 2013 Automatic Build System 2.4.50-1mamba +- automatic version update by autodist + +* Sat Nov 23 2013 Automatic Build System 2.4.49-1mamba +- automatic version update by autodist + +* Tue Nov 19 2013 Automatic Build System 2.4.48-1mamba +- automatic version update by autodist + +* Sun Oct 13 2013 Automatic Build System 2.4.47-1mamba +- automatic version update by autodist + +* Wed Jul 03 2013 Automatic Build System 2.4.46-1mamba +- automatic version update by autodist + +* Sat May 18 2013 Automatic Build System 2.4.45-1mamba +- automatic version update by autodist + +* Fri Apr 19 2013 Automatic Build System 2.4.44-1mamba +- automatic version update by autodist + +* Thu Feb 07 2013 Automatic Build System 2.4.42-1mamba +- automatic version update by autodist + +* Sat Jan 26 2013 Automatic Build System 2.4.41-1mamba +- automatic version update by autodist + +* Sun Nov 25 2012 Automatic Build System 2.4.40-1mamba +- automatic version update by autodist + +* Mon Sep 24 2012 Automatic Build System 2.4.39-1mamba +- automatic version update by autodist + +* Fri Aug 24 2012 Silvan Calarco 2.4.38-2mamba +- bump epoch up to follow libdrm 2.4.33 revert + +* Sat Aug 18 2012 Automatic Build System 2.4.38-1mamba +- automatic version update by autodist + +* Fri Jul 27 2012 Silvan Calarco 2.4.37-1mamba +- update to 2.4.37 +- added patch to build libdrm_nouveau.so.1 compatibility library + +* Thu Jun 28 2012 Silvan Calarco 2.4.36-1mamba +- update to 2.4.36 + +* Fri Jun 01 2012 Silvan Calarco 2.4.33-1mamba +- update to 2.4.33 + +* Fri Feb 17 2012 Silvan Calarco 2.4.31-1mamba +- update to 2.4.31 + +* Sun Jan 22 2012 Silvan Calarco 2.4.30-1mamba +- update to 2.4.30 + +* Sun Jun 19 2011 Automatic Build System 2.4.26-1mamba +- automatic update by autodist + +* Mon May 16 2011 Silvan Calarco 2.4.25-1mamba +- update to 2.4.25 + +* Thu Feb 24 2011 Silvan Calarco 2.4.23-2mamba +- added patches to fix support for i8xx gen2 intel GPU's + +* Sat Feb 05 2011 Silvan Calarco 2.4.23-1mamba +- update to 2.4.23 + +* Tue Oct 05 2010 Silvan Calarco 2.4.22-1mamba +- update to 2.4.22 + +* Tue Jun 22 2010 Automatic Build System 2.4.21-1mamba +- automatic update by autodist + +* Mon Jan 25 2010 Automatic Build System 2.4.17-1mamba +- automatic update by autodist + +* Thu Oct 15 2009 Automatic Build System 2.4.15-1mamba +- automatic update by autodist + +* Tue Sep 01 2009 Automatic Build System 2.4.13-1mamba +- automatic update by autodist + +* Thu Aug 13 2009 Silvan Calarco 2.4.12-2mamba +- exclude drm_mode.h provided by glibc headers from kernel 2.6.30 + +* Thu Jul 23 2009 Automatic Build System 2.4.12-1mamba +- automatic update by autodist + +* Sat Jun 20 2009 Silvan Calarco 2.4.11-4mamba +- rebuilt after kernel 2.6.29 update + +* Sat Jun 20 2009 Silvan Calarco 2.4.11-3mamba +- added radeon patch + +* Fri Jun 19 2009 Silvan Calarco 2.4.11-2mamba +- added missing headers + +* Mon May 18 2009 Automatic Build System 2.4.11-1mamba +- automatic update by autodist + +* Thu Apr 16 2009 Silvan Calarco 2.4.9-2mamba +- rebuilt with --enable-udev and --enable-nouveau-experimental-api +- excluded header files conflicting with the ones from kernel headers + +* Wed Apr 15 2009 Silvan Calarco 2.4.9-1mamba +- update to 2.4.9 + +* Tue Mar 10 2009 Silvan Calarco 2.4.5-1mamba +- automatic update by autodist + +* Thu Jan 08 2009 Silvan Calarco 2.4.3-1mamba +- automatic update by autodist + +* Tue May 20 2008 Silvan Calarco 2.3.0-2mamba +- specfile updated + +* Wed Dec 20 2006 Silvan Calarco 2.3.0-1qilnx +- update to version 2.3.0 by autospec + +* Wed Oct 25 2006 Silvan Calarco 2.0.2-1qilnx +- package created by autospec