libdrm: Changes to 'ubuntu'
.gitignore | 2
ChangeLog | 469
Makefile.am | 6
configure.ac | 40
debian/changelog | 53
debian/patches/03_revert_abi_change.diff | 1220 ++
debian/patches/03_update_nouveau_defines_1.diff | 1620 --
debian/patches/04_update_nouveau_defines_2.diff | 4032 -------
debian/patches/05_update_nouveau_defines_3.diff | 117
debian/patches/06_nouveau_free_objects_on_channel_close.diff | 78
debian/patches/07_nouveau_fix_mem_leak_on_channel_free.diff | 28
debian/patches/08_nouveau_no_flush_notify_on_channel_free.diff | 22
debian/patches/09_add_BEGIN_RING_NI.diff | 25
debian/patches/series | 8
include/drm/Makefile.am | 5
include/drm/nouveau_drm.h | 87
include/drm/vmwgfx_drm.h | 574 +
intel/intel_atomic.h | 15
intel/intel_bufmgr_fake.c | 5
intel/intel_bufmgr_gem.c | 27
intel/libdrm_intel.pc.in | 3
libkms/Makefile.am | 29
libkms/api.c | 138
libkms/intel.c | 240
libkms/internal.h | 71
libkms/libkms.h | 74
libkms/libkms.pc.in | 10
libkms/linux.c | 215
libkms/vmwgfx.c | 207
nouveau/Makefile.am | 6
nouveau/nouveau_bo.c | 83
nouveau/nouveau_bo.h | 14
nouveau/nouveau_channel.c | 12
nouveau/nouveau_channel.h | 5
nouveau/nouveau_class.h | 5408 +++++-----
nouveau/nouveau_device.c | 8
nouveau/nouveau_private.h | 15
nouveau/nouveau_pushbuf.c | 385
nouveau/nouveau_pushbuf.h | 34
nouveau/nouveau_reloc.c | 132
nouveau/nouveau_reloc.h | 32
nouveau/nouveau_resource.c | 9
nouveau/nouveau_resource.h | 3
radeon/libdrm_radeon.pc.in | 2
radeon/radeon_bo.c | 60
radeon/radeon_bo.h | 24
radeon/radeon_bo_gem.c | 32
radeon/radeon_bo_gem.h | 8
radeon/radeon_bo_int.h | 4
radeon/radeon_cs.c | 38
radeon/radeon_cs.h | 48
radeon/radeon_cs_gem.c | 153
radeon/radeon_cs_gem.h | 8
radeon/radeon_cs_space.c | 170
tests/Makefile.am | 4
tests/dristat.c | 3
tests/drmstat.c | 10
tests/drmtest.c | 4
tests/kmstest/Makefile.am | 17
tests/kmstest/main.c | 90
tests/modeprint/modeprint.c | 8
tests/modetest/modetest.c | 38
xf86drmMode.c | 129
xf86drmMode.h | 2
xf86drmSL.c | 3
65 files changed, 7246 insertions(+), 9175 deletions(-)
New commits:
commit ed306d4f575b18b8f0981fee2e23ca06d577af94
Author: Timo Aaltonen <tjaalton@cc.hut.fi>
Date: Fri Feb 19 14:19:17 2010 +0200
Release 2.4.18-1ubuntu1
diff --git a/debian/changelog b/debian/changelog
index aed09ba..2692d93 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,11 +1,11 @@
-libdrm (2.4.18-1ubuntu1) UNRELEASED; urgency=low
+libdrm (2.4.18-1ubuntu1) lucid; urgency=low
* Merge from Debian unstable.
* Remove the nouveau patches, since they are included in this version.
* Add 03_revert_abi_change.diff to revert the nouveau ABI change.
We need the old ABI until the kernel has been updated.
- -- Timo Aaltonen <tjaalton@ubuntu.com> Fri, 19 Feb 2010 14:14:45 +0200
+ -- Timo Aaltonen <tjaalton@ubuntu.com> Fri, 19 Feb 2010 14:19:08 +0200
libdrm (2.4.18-1) unstable; urgency=low
commit 16a75483cd4ae1a2282a76eabe7f97252b4a4906
Author: Timo Aaltonen <tjaalton@cc.hut.fi>
Date: Fri Feb 19 14:19:02 2010 +0200
Merge from Debian unstable.
* Remove the nouveau patches, since they are included in this version.
* Add 03_revert_abi_change.diff to revert the nouveau ABI change.
We need the old ABI until the kernel has been updated.
diff --git a/debian/changelog b/debian/changelog
index af2807e..aed09ba 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,12 @@
+libdrm (2.4.18-1ubuntu1) UNRELEASED; urgency=low
+
+ * Merge from Debian unstable.
+ * Remove the nouveau patches, since they are included in this version.
+ * Add 03_revert_abi_change.diff to revert the nouveau ABI change.
+ We need the old ABI until the kernel has been updated.
+
+ -- Timo Aaltonen <tjaalton@ubuntu.com> Fri, 19 Feb 2010 14:14:45 +0200
+
libdrm (2.4.18-1) unstable; urgency=low
* New upstream release.
diff --git a/debian/patches/03_revert_abi_change.diff b/debian/patches/03_revert_abi_change.diff
new file mode 100644
index 0000000..d91d8e5
--- /dev/null
+++ b/debian/patches/03_revert_abi_change.diff
@@ -0,0 +1,1220 @@
+diff --git a/include/drm/nouveau_drm.h b/include/drm/nouveau_drm.h
+index a6a9f4a..f745948 100644
+--- a/include/drm/nouveau_drm.h
++++ b/include/drm/nouveau_drm.h
+@@ -25,14 +25,13 @@
+ #ifndef __NOUVEAU_DRM_H__
+ #define __NOUVEAU_DRM_H__
+
+-#define NOUVEAU_DRM_HEADER_PATCHLEVEL 16
++#define NOUVEAU_DRM_HEADER_PATCHLEVEL 15
+
+ struct drm_nouveau_channel_alloc {
+ uint32_t fb_ctxdma_handle;
+ uint32_t tt_ctxdma_handle;
+
+ int channel;
+- uint32_t pushbuf_domains;
+
+ /* Notifier memory */
+ uint32_t notifier_handle;
+@@ -110,58 +109,68 @@ struct drm_nouveau_gem_new {
+ uint32_t align;
+ };
+
+-#define NOUVEAU_GEM_MAX_BUFFERS 1024
+-struct drm_nouveau_gem_pushbuf_bo_presumed {
+- uint32_t valid;
+- uint32_t domain;
+- uint64_t offset;
+-};
+-
+ struct drm_nouveau_gem_pushbuf_bo {
+ uint64_t user_priv;
+ uint32_t handle;
+ uint32_t read_domains;
+ uint32_t write_domains;
+ uint32_t valid_domains;
+- struct drm_nouveau_gem_pushbuf_bo_presumed presumed;
++ uint32_t presumed_ok;
++ uint32_t presumed_domain;
++ uint64_t presumed_offset;
+ };
+
+ #define NOUVEAU_GEM_RELOC_LOW (1 << 0)
+ #define NOUVEAU_GEM_RELOC_HIGH (1 << 1)
+ #define NOUVEAU_GEM_RELOC_OR (1 << 2)
+-#define NOUVEAU_GEM_MAX_RELOCS 1024
+ struct drm_nouveau_gem_pushbuf_reloc {
+- uint32_t reloc_bo_index;
+- uint32_t reloc_bo_offset;
+ uint32_t bo_index;
++ uint32_t reloc_index;
+ uint32_t flags;
+ uint32_t data;
+ uint32_t vor;
+ uint32_t tor;
+ };
+
+-#define NOUVEAU_GEM_MAX_PUSH 512
+-struct drm_nouveau_gem_pushbuf_push {
+- uint32_t bo_index;
+- uint32_t pad;
+- uint64_t offset;
+- uint64_t length;
+-};
++#define NOUVEAU_GEM_MAX_BUFFERS 1024
++#define NOUVEAU_GEM_MAX_RELOCS 1024
+
+ struct drm_nouveau_gem_pushbuf {
+ uint32_t channel;
++ uint32_t nr_dwords;
+ uint32_t nr_buffers;
++ uint32_t nr_relocs;
++ uint64_t dwords;
+ uint64_t buffers;
++ uint64_t relocs;
++};
++
++struct drm_nouveau_gem_pushbuf_call {
++ uint32_t channel;
++ uint32_t handle;
++ uint32_t offset;
++ uint32_t nr_buffers;
+ uint32_t nr_relocs;
+- uint32_t nr_push;
++ uint32_t nr_dwords;
++ uint64_t buffers;
+ uint64_t relocs;
+- uint64_t push;
+ uint32_t suffix0;
+ uint32_t suffix1;
++ /* below only accessed for CALL2 */
+ uint64_t vram_available;
+ uint64_t gart_available;
+ };
+
++struct drm_nouveau_gem_pin {
++ uint32_t handle;
++ uint32_t domain;
++ uint64_t offset;
++};
++
++struct drm_nouveau_gem_unpin {
++ uint32_t handle;
++};
++
+ #define NOUVEAU_GEM_CPU_PREP_NOWAIT 0x00000001
+ #define NOUVEAU_GEM_CPU_PREP_NOBLOCK 0x00000002
+ #define NOUVEAU_GEM_CPU_PREP_WRITE 0x00000004
+@@ -174,6 +183,14 @@ struct drm_nouveau_gem_cpu_fini {
+ uint32_t handle;
+ };
+
++struct drm_nouveau_gem_tile {
++ uint32_t handle;
++ uint32_t offset;
++ uint32_t size;
++ uint32_t tile_mode;
++ uint32_t tile_flags;
++};
++
+ enum nouveau_bus_type {
+ NV_AGP = 0,
+ NV_PCI = 1,
+@@ -183,17 +200,22 @@ enum nouveau_bus_type {
+ struct drm_nouveau_sarea {
+ };
+
+-#define DRM_NOUVEAU_GETPARAM 0x00
+-#define DRM_NOUVEAU_SETPARAM 0x01
+-#define DRM_NOUVEAU_CHANNEL_ALLOC 0x02
+-#define DRM_NOUVEAU_CHANNEL_FREE 0x03
+-#define DRM_NOUVEAU_GROBJ_ALLOC 0x04
+-#define DRM_NOUVEAU_NOTIFIEROBJ_ALLOC 0x05
+-#define DRM_NOUVEAU_GPUOBJ_FREE 0x06
++#define DRM_NOUVEAU_CARD_INIT 0x00
++#define DRM_NOUVEAU_GETPARAM 0x01
++#define DRM_NOUVEAU_SETPARAM 0x02
++#define DRM_NOUVEAU_CHANNEL_ALLOC 0x03
++#define DRM_NOUVEAU_CHANNEL_FREE 0x04
++#define DRM_NOUVEAU_GROBJ_ALLOC 0x05
++#define DRM_NOUVEAU_NOTIFIEROBJ_ALLOC 0x06
++#define DRM_NOUVEAU_GPUOBJ_FREE 0x07
+ #define DRM_NOUVEAU_GEM_NEW 0x40
+ #define DRM_NOUVEAU_GEM_PUSHBUF 0x41
+-#define DRM_NOUVEAU_GEM_CPU_PREP 0x42
+-#define DRM_NOUVEAU_GEM_CPU_FINI 0x43
+-#define DRM_NOUVEAU_GEM_INFO 0x44
++#define DRM_NOUVEAU_GEM_PUSHBUF_CALL 0x42
++#define DRM_NOUVEAU_GEM_PIN 0x43 /* !KMS only */
++#define DRM_NOUVEAU_GEM_UNPIN 0x44 /* !KMS only */
++#define DRM_NOUVEAU_GEM_CPU_PREP 0x45
++#define DRM_NOUVEAU_GEM_CPU_FINI 0x46
++#define DRM_NOUVEAU_GEM_INFO 0x47
++#define DRM_NOUVEAU_GEM_PUSHBUF_CALL2 0x48
+
+ #endif /* __NOUVEAU_DRM_H__ */
+diff --git a/nouveau/Makefile.am b/nouveau/Makefile.am
+index 5d759c5..70bbbb2 100644
+--- a/nouveau/Makefile.am
++++ b/nouveau/Makefile.am
+@@ -18,8 +18,7 @@ libdrm_nouveau_la_SOURCES = \
+ nouveau_notifier.c \
+ nouveau_bo.c \
+ nouveau_resource.c \
+- nouveau_private.h \
+- nouveau_reloc.c
++ nouveau_private.h
+
+ libdrm_nouveaucommonincludedir = ${includedir}/nouveau
+ libdrm_nouveaucommoninclude_HEADERS = \
+@@ -30,8 +29,7 @@ libdrm_nouveaucommoninclude_HEADERS = \
+ nouveau_pushbuf.h \
+ nouveau_bo.h \
+ nouveau_resource.h \
+- nouveau_class.h \
+- nouveau_reloc.h
++ nouveau_class.h
+
+
+ libdrm_nouveauincludedir = ${includedir}/drm
+diff --git a/nouveau/nouveau_bo.c b/nouveau/nouveau_bo.c
+index 4973636..10cc8a6 100644
+--- a/nouveau/nouveau_bo.c
++++ b/nouveau/nouveau_bo.c
+@@ -201,6 +201,14 @@ nouveau_bo_new_tile(struct nouveau_device *dev, uint32_t flags, int align,
+ nouveau_bo_ref(NULL, (void *)nvbo);
+ return ret;
+ }
++
++ if (flags & NOUVEAU_BO_PIN) {
++ ret = nouveau_bo_pin((void *)nvbo, nvbo->flags);
++ if (ret) {
++ nouveau_bo_ref(NULL, (void *)nvbo);
++ return ret;
++ }
++ }
+ }
+
+ *bo = &nvbo->base;
+@@ -211,7 +219,16 @@ 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);
++ uint32_t tile_flags = 0;
++
++ if (flags & NOUVEAU_BO_TILED) {
++ if (flags & NOUVEAU_BO_ZTILE)
++ tile_flags = 0x2800;
++ else
++ tile_flags = 0x7000;
++ }
++
++ return nouveau_bo_new_tile(dev, flags, align, size, 0, tile_flags, bo);
+ }
+
+ int
+@@ -466,6 +483,62 @@ nouveau_bo_unmap(struct nouveau_bo *bo)
+ }
+
+ int
++nouveau_bo_pin(struct nouveau_bo *bo, uint32_t flags)
++{
++ struct nouveau_device_priv *nvdev = nouveau_device(bo->device);
++ struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
++ struct drm_nouveau_gem_pin req;
++ int ret;
++
++ if (nvbo->pinned)
++ return 0;
++
++ if (!nvbo->handle)
++ return -EINVAL;
++
++ /* Now force it to stay put :) */
++ req.handle = nvbo->handle;
++ req.domain = 0;
++ if (flags & NOUVEAU_BO_VRAM)
++ req.domain |= NOUVEAU_GEM_DOMAIN_VRAM;
++ if (flags & NOUVEAU_BO_GART)
++ req.domain |= NOUVEAU_GEM_DOMAIN_GART;
++
++ ret = drmCommandWriteRead(nvdev->fd, DRM_NOUVEAU_GEM_PIN, &req,
++ sizeof(struct drm_nouveau_gem_pin));
++ if (ret)
++ return ret;
++ nvbo->offset = req.offset;
++ nvbo->domain = req.domain;
++ nvbo->pinned = 1;
++
++ /* Fill in public nouveau_bo members */
++ if (nvbo->domain & NOUVEAU_GEM_DOMAIN_VRAM)
++ bo->flags = NOUVEAU_BO_VRAM;
++ if (nvbo->domain & NOUVEAU_GEM_DOMAIN_GART)
++ bo->flags = NOUVEAU_BO_GART;
++ bo->offset = nvbo->offset;
++
++ return 0;
++}
++
++void
++nouveau_bo_unpin(struct nouveau_bo *bo)
++{
++ struct nouveau_device_priv *nvdev = nouveau_device(bo->device);
++ struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
++ struct drm_nouveau_gem_unpin req;
++
++ if (!nvbo->pinned)
++ return;
++
++ req.handle = nvbo->handle;
++ drmCommandWrite(nvdev->fd, DRM_NOUVEAU_GEM_UNPIN, &req, sizeof(req));
++
++ nvbo->pinned = bo->offset = bo->flags = 0;
++}
++
++int
+ nouveau_bo_busy(struct nouveau_bo *bo, uint32_t access)
+ {
+ return nouveau_bo_wait(bo, (access & NOUVEAU_BO_WR), 1, 1);
+@@ -492,7 +565,7 @@ nouveau_bo_pending(struct nouveau_bo *bo)
+ 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_pushbuf_priv *nvpb = nouveau_pushbuf(chan->pushbuf);
+ struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
+ struct drm_nouveau_gem_pushbuf_bo *pbbo;
+ struct nouveau_bo *ref = NULL;
+@@ -534,8 +607,8 @@ nouveau_bo_emit_buffer(struct nouveau_channel *chan, struct nouveau_bo *bo)
+ 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;
++ pbbo->presumed_domain = nvbo->domain;
++ pbbo->presumed_offset = nvbo->offset;
++ pbbo->presumed_ok = 1;
+ return pbbo;
+ }
+diff --git a/nouveau/nouveau_bo.h b/nouveau/nouveau_bo.h
+index 1e77ab0..fdad63e 100644
+--- a/nouveau/nouveau_bo.h
++++ b/nouveau/nouveau_bo.h
+@@ -30,9 +30,13 @@
+ #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_PIN (1 << 5)
+ #define NOUVEAU_BO_LOW (1 << 6)
+ #define NOUVEAU_BO_HIGH (1 << 7)
+ #define NOUVEAU_BO_OR (1 << 8)
++#define NOUVEAU_BO_LOCAL (1 << 9)
++#define NOUVEAU_BO_TILED (1 << 10)
++#define NOUVEAU_BO_ZTILE (1 << 11)
+ #define NOUVEAU_BO_INVAL (1 << 12)
+ #define NOUVEAU_BO_NOSYNC (1 << 13)
+ #define NOUVEAU_BO_NOWAIT (1 << 14)
+@@ -48,6 +52,10 @@ struct nouveau_bo {
+
+ uint32_t tile_mode;
+ uint32_t tile_flags;
++
++ /* Available when buffer is pinned *only* */
++ uint32_t flags;
++ uint64_t offset;
+ };
+
+ int
+@@ -90,6 +98,12 @@ void
+ nouveau_bo_unmap(struct nouveau_bo *);
+
+ int
++nouveau_bo_pin(struct nouveau_bo *, uint32_t flags);
++
++void
++nouveau_bo_unpin(struct nouveau_bo *);
++
++int
+ nouveau_bo_busy(struct nouveau_bo *, uint32_t access);
+
+ uint32_t
+diff --git a/nouveau/nouveau_channel.h b/nouveau/nouveau_channel.h
+index ddcf8e4..294f749 100644
+--- a/nouveau/nouveau_channel.h
++++ b/nouveau/nouveau_channel.h
+@@ -29,12 +29,11 @@ struct nouveau_subchannel {
+ };
+
+ struct nouveau_channel {
+- uint32_t *cur;
+- uint32_t *end;
+-
+ struct nouveau_device *device;
+ int id;
+
++ struct nouveau_pushbuf *pushbuf;
++
+ struct nouveau_grobj *nullobj;
+ struct nouveau_grobj *vram;
+ struct nouveau_grobj *gart;
+diff --git a/nouveau/nouveau_device.c b/nouveau/nouveau_device.c
+index c525391..0982d3b 100644
+--- a/nouveau/nouveau_device.c
++++ b/nouveau/nouveau_device.c
+@@ -26,7 +26,7 @@
+
+ #include "nouveau_private.h"
+
+-#if NOUVEAU_DRM_HEADER_PATCHLEVEL != 16
++#if NOUVEAU_DRM_HEADER_PATCHLEVEL != 15
+ #error nouveau_drm.h does not match expected patchlevel, update libdrm.
+ #endif
+
+@@ -54,6 +54,12 @@ nouveau_device_open_existing(struct nouveau_device **dev, int close,
+ nvdev->ctx = ctx;
+ nvdev->needs_close = close;
+
++ ret = drmCommandNone(nvdev->fd, DRM_NOUVEAU_CARD_INIT);
++ if (ret) {
++ nouveau_device_close((void *)&nvdev);
++ return ret;
++ }
++
+ ret = nouveau_device_get_param(&nvdev->base,
+ NOUVEAU_GETPARAM_VM_VRAM_BASE, &value);
+ if (ret) {
+diff --git a/nouveau/nouveau_private.h b/nouveau/nouveau_private.h
+index c08fa38..39758d1 100644
+--- a/nouveau/nouveau_private.h
++++ b/nouveau/nouveau_private.h
+@@ -35,11 +35,14 @@
+ #include "nouveau_bo.h"
+ #include "nouveau_resource.h"
+ #include "nouveau_pushbuf.h"
+-#include "nouveau_reloc.h"
+
+ #define CALPB_BUFFERS 4
+ #define CALPB_BUFSZ 16384
+ struct nouveau_pushbuf_priv {
++ struct nouveau_pushbuf base;
++
++ int no_aper_update;
++ int use_cal;
+ uint32_t cal_suffix0;
+ uint32_t cal_suffix1;
+ struct nouveau_bo *buffer[CALPB_BUFFERS];
+@@ -47,19 +50,15 @@ struct nouveau_pushbuf_priv {
+ int current_offset;
+
+ unsigned *pushbuf;
+- unsigned size;
++ unsigned size;
+
+- uint32_t *marker;
+- unsigned marker_offset;
++ unsigned marker;
+ 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))
+
+diff --git a/nouveau/nouveau_pushbuf.c b/nouveau/nouveau_pushbuf.c
+index 28b8018..7da3a47 100644
+--- a/nouveau/nouveau_pushbuf.c
++++ b/nouveau/nouveau_pushbuf.c
+@@ -31,7 +31,7 @@
+ #define PB_MIN_USER_DWORDS 2048
+
+ static int
+-nouveau_pushbuf_space(struct nouveau_channel *chan, unsigned min)
++nouveau_pushbuf_space_call(struct nouveau_channel *chan, unsigned min)
+ {
+ struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
+ struct nouveau_pushbuf_priv *nvpb = &nvchan->pb;
+@@ -41,8 +41,8 @@ nouveau_pushbuf_space(struct nouveau_channel *chan, unsigned min)
+ 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)
++ nvpb->current_offset = nvpb->base.cur - nvpb->pushbuf;
++ if (nvpb->current_offset + min + 2 <= nvpb->size)
+ return 0;
+
+ nvpb->current++;
+@@ -58,13 +58,38 @@ nouveau_pushbuf_space(struct nouveau_channel *chan, unsigned min)
+ nvpb->pushbuf = bo->map;
+ nvpb->current_offset = 0;
+
+- chan->cur = nvpb->pushbuf;
+- chan->end = nvpb->pushbuf + nvpb->size;
++ nvpb->base.channel = chan;
++ nvpb->base.remaining = nvpb->size;
++ nvpb->base.cur = nvpb->pushbuf;
+
+ nouveau_bo_unmap(bo);
+ return 0;
+ }
+
++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;
++
++ if (nvpb->use_cal)
++ return nouveau_pushbuf_space_call(chan, min);
++
++ if (nvpb->pushbuf) {
++ free(nvpb->pushbuf);
++ nvpb->pushbuf = NULL;
++ }
++
++ nvpb->size = min < PB_MIN_USER_DWORDS ? PB_MIN_USER_DWORDS : min;
++ nvpb->pushbuf = malloc(sizeof(uint32_t) * nvpb->size);
++
++ nvpb->base.channel = chan;
++ nvpb->base.remaining = nvpb->size;
++ nvpb->base.cur = nvpb->pushbuf;
++
++ return 0;
++}
++
+ static void
+ nouveau_pushbuf_fini_call(struct nouveau_channel *chan)
+ {
+@@ -74,43 +99,46 @@ nouveau_pushbuf_fini_call(struct nouveau_channel *chan)
+
+ for (i = 0; i < CALPB_BUFFERS; i++)
+ nouveau_bo_ref(NULL, &nvpb->buffer[i]);
++ nvpb->use_cal = 0;
+ nvpb->pushbuf = NULL;
+ }
+
+-static int
++static void
+ nouveau_pushbuf_init_call(struct nouveau_channel *chan)
+ {
+- struct drm_nouveau_gem_pushbuf req;
++ struct drm_nouveau_gem_pushbuf_call 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;
++ req.handle = 0;
+ ret = drmCommandWriteRead(nouveau_device(dev)->fd,
+- DRM_NOUVEAU_GEM_PUSHBUF, &req, sizeof(req));
+- if (ret)
+- return ret;
++ DRM_NOUVEAU_GEM_PUSHBUF_CALL2,
++ &req, sizeof(req));
++ if (ret) {
++ ret = drmCommandWriteRead(nouveau_device(dev)->fd,
++ DRM_NOUVEAU_GEM_PUSHBUF_CALL2,
++ &req, sizeof(req));
++ if (ret)
++ return;
++
++ nvpb->no_aper_update = 1;
++ }
+
+ for (i = 0; i < CALPB_BUFFERS; i++) {
+- ret = nouveau_bo_new(dev, flags | NOUVEAU_BO_MAP,
++ ret = nouveau_bo_new(dev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP,
+ 0, CALPB_BUFSZ, &nvpb->buffer[i]);
+ if (ret) {
+ nouveau_pushbuf_fini_call(chan);
+- return ret;
++ return;
+ }
+ }
+
++ nvpb->use_cal = 1;
+ nvpb->cal_suffix0 = req.suffix0;
+ nvpb->cal_suffix1 = req.suffix1;
+- return 0;
+ }
+
+ int
+@@ -120,18 +148,25 @@ nouveau_pushbuf_init(struct nouveau_channel *chan)
+ struct nouveau_pushbuf_priv *nvpb = &nvchan->pb;
+ int ret;
+
+- ret = nouveau_pushbuf_init_call(chan);
+- if (ret)
+- return ret;
++ nouveau_pushbuf_init_call(chan);
+
+ ret = nouveau_pushbuf_space(chan, 0);
+- if (ret)
+- return ret;
++ if (ret) {
++ if (nvpb->use_cal) {
++ nouveau_pushbuf_fini_call(chan);
++ 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));
++
++ chan->pushbuf = &nvpb->base;
+ return 0;
+ }
+
+@@ -145,129 +180,92 @@ nouveau_pushbuf_fini(struct nouveau_channel *chan)
+ 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)
++ if (nvpb->base.remaining == nvpb->size)
+ 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,
++ if (nvpb->use_cal) {
++ struct drm_nouveau_gem_pushbuf_call req;
++
++ *(nvpb->base.cur++) = nvpb->cal_suffix0;
++ *(nvpb->base.cur++) = nvpb->cal_suffix1;
++ if (nvpb->base.remaining > 2) /* space() will fixup if not */
++ nvpb->base.remaining -= 2;
++
++restart_cal:
++ req.channel = chan->id;
++ req.handle = nvpb->buffer[nvpb->current]->handle;
++ req.offset = nvpb->current_offset * 4;
++ 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.nr_dwords = (nvpb->base.cur - nvpb->pushbuf) -
++ nvpb->current_offset;
++ req.suffix0 = nvpb->cal_suffix0;
++ req.suffix1 = nvpb->cal_suffix1;
++ ret = drmCommandWriteRead(nvdev->fd, nvpb->no_aper_update ?
++ DRM_NOUVEAU_GEM_PUSHBUF_CALL :
++ DRM_NOUVEAU_GEM_PUSHBUF_CALL2,
+ &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;
++ if (ret == -EAGAIN)
++ goto restart_cal;
++ nvpb->cal_suffix0 = req.suffix0;
++ nvpb->cal_suffix1 = req.suffix1;
++ if (!nvpb->no_aper_update) {
++ nvdev->base.vm_vram_size = req.vram_available;
++ nvdev->base.vm_gart_size = req.gart_available;
++ }
++ } else {
++ struct drm_nouveau_gem_pushbuf req;
++
++restart_push:
++ req.channel = chan->id;
++ req.nr_dwords = nvpb->size - nvpb->base.remaining;
++ req.dwords = (uint64_t)(unsigned long)nvpb->pushbuf;
++ 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;
++ ret = drmCommandWrite(nvdev->fd, DRM_NOUVEAU_GEM_PUSHBUF,
++ &req, sizeof(req));
++ if (ret == -EAGAIN)
++ goto restart_push;
++ }
++
+
+ /* 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);
+- }
++ struct drm_nouveau_gem_pushbuf_reloc *r = &nvpb->relocs[i];
++ struct drm_nouveau_gem_pushbuf_bo *pbbo =
++ &nvpb->buffers[r->bo_index];
++ struct nouveau_bo *bo = (void *)(unsigned long)pbbo->user_priv;
++ struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
++
++ if (--nvbo->pending_refcnt)
++ continue;
++
++ if (pbbo->presumed_ok == 0) {
++ nvbo->domain = pbbo->presumed_domain;
++ nvbo->offset = pbbo->presumed_offset;
++ }
+
+- for (i = 0; i < nvpb->nr_push; i++)
+- nouveau_pushbuf_bo_unref(nvpb, nvpb->push[i].bo_index);
++ nvbo->pending = NULL;
++ nouveau_bo_ref(NULL, &bo);
++ }
+
+ nvpb->nr_buffers = 0;
+ nvpb->nr_relocs = 0;
+- nvpb->nr_push = 0;
+
+ /* Allocate space for next push buffer */
+ assert(!nouveau_pushbuf_space(chan, min));
+@@ -275,7 +273,7 @@ nouveau_pushbuf_flush(struct nouveau_channel *chan, unsigned min)
+ if (chan->flush_notify)
+ chan->flush_notify(chan);
+
+- nvpb->marker = NULL;
++ nvpb->marker = 0;
+ return ret;
+ }
+
+@@ -283,7 +281,7 @@ int
+ nouveau_pushbuf_marker_emit(struct nouveau_channel *chan,
+ unsigned wait_dwords, unsigned wait_relocs)
+ {
+- struct nouveau_pushbuf_priv *nvpb = &nouveau_channel(chan)->pb;
++ struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(chan->pushbuf);
+
+ if (AVAIL_RING(chan) < wait_dwords)
+ return nouveau_pushbuf_flush(chan, wait_dwords);
+@@ -291,9 +289,7 @@ nouveau_pushbuf_marker_emit(struct nouveau_channel *chan,
+ 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 = nvpb->base.cur - nvpb->pushbuf;
+ nvpb->marker_relocs = nvpb->nr_relocs;
+ return 0;
+ }
+@@ -301,7 +297,7 @@ nouveau_pushbuf_marker_emit(struct nouveau_channel *chan,
+ void
+ nouveau_pushbuf_marker_undo(struct nouveau_channel *chan)
+ {
+- struct nouveau_pushbuf_priv *nvpb = &nouveau_channel(chan)->pb;
++ struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(chan->pushbuf);
+ unsigned i;
+
+ if (!nvpb->marker)
+@@ -309,19 +305,49 @@ nouveau_pushbuf_marker_undo(struct nouveau_channel *chan)
+
+ /* 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);
++ struct drm_nouveau_gem_pushbuf_reloc *r = &nvpb->relocs[i];
++ struct drm_nouveau_gem_pushbuf_bo *pbbo =
++ &nvpb->buffers[r->bo_index];
++ struct nouveau_bo *bo = (void *)(unsigned long)pbbo->user_priv;
++ struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
++
++ if (--nvbo->pending_refcnt)
++ continue;
++
++ nvbo->pending = NULL;
++ nouveau_bo_ref(NULL, &bo);
++ nvpb->nr_buffers--;
+ }
+ 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;
++ nvpb->base.cur = nvpb->pushbuf + nvpb->marker;
++ nvpb->base.remaining = nvpb->size - nvpb->marker;
++ nvpb->marker = 0;
++}
++
++static uint32_t
++nouveau_pushbuf_calc_reloc(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
Reply to: