[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

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: