Merge branch 'drm-next-4.2-amdgpu' of git://people.freedesktop.org/~agd5f/linux into drm-next

This is the big pull request for amdgpu, the new driver for VI+ AMD
asics.  I currently supports Tonga, Iceland, and Carrizo and also
contains a Kconfig option to build support for CI parts for testing.

All major functionality is supported (displays, gfx, compute, dma,
video decode/encode, etc.).  Power management is working on Carrizo,
but is still being worked on for Tonga and Iceland.

* 'drm-next-4.2-amdgpu' of git://people.freedesktop.org/~agd5f/linux: (106 commits)
  drm/amdgpu: only support IBs in the buffer list (v2)
  drm/amdgpu: add vram_type and vram_bit_width for interface query (v2)
  drm/amdgpu: add ib_size/start_alignment interface query
  drm/amdgpu: add me/ce/pfp_feature_version interface query
  drm/amdgpu add ce_ram_size for interface query
  drm/amdgpu add max_memory_clock for interface query (v2)
  drm/amdgpu: add hdp flush for gfx8 compute ring
  drm/amdgpu: fix no hdp flush for compute ring
  drm/amdgpu: add HEVC/H.265 UVD support
  drm/amdgpu: stop loading firmware with pm.mutex locked
  drm/amdgpu: remove mclk_lock
  drm/amdgpu: fix description of vm_size module parameter (v2)
  drm/amdgpu: remove all sh mem register modification in vm flush
  drm/amdgpu: rename GEM_OP_SET_INITIAL_DOMAIN -> GEM_OP_SET_PLACEMENT
  drm/amdgpu: fence should be added to shared slot
  drm/amdgpu: sync fence of clear_invalids (v2)
  drm/amdgpu: max_pde_used usage should be under protect
  drm/amdgpu: fix bug of vm_bo_map (v2)
  drm/amdgpu: implement the allocation range (v3)
  drm/amdgpu: rename amdgpu_ip_funcs to amd_ip_funcs (v2)
  ...
diff --git a/drivers/gpu/drm/qxl/qxl_cmd.c b/drivers/gpu/drm/qxl/qxl_cmd.c
index 9782364..fdc1833 100644
--- a/drivers/gpu/drm/qxl/qxl_cmd.c
+++ b/drivers/gpu/drm/qxl/qxl_cmd.c
@@ -248,7 +248,7 @@
 		}
 	}
 
-	QXL_INFO(qdev, "%s: %lld\n", __func__, i);
+	QXL_INFO(qdev, "%s: %d\n", __func__, i);
 
 	return i;
 }
@@ -505,6 +505,7 @@
 
 	cmd = (struct qxl_surface_cmd *)qxl_release_map(qdev, release);
 	cmd->type = QXL_SURFACE_CMD_CREATE;
+	cmd->flags = QXL_SURF_FLAG_KEEP_DATA;
 	cmd->u.surface_create.format = surf->surf.format;
 	cmd->u.surface_create.width = surf->surf.width;
 	cmd->u.surface_create.height = surf->surf.height;
@@ -617,8 +618,8 @@
 	int ret;
 
 	ret = qxl_bo_reserve(surf, false);
-	if (ret == -EBUSY)
-		return -EBUSY;
+	if (ret)
+		return ret;
 
 	if (stall)
 		mutex_unlock(&qdev->surf_evict_mutex);
@@ -627,9 +628,9 @@
 
 	if (stall)
 		mutex_lock(&qdev->surf_evict_mutex);
-	if (ret == -EBUSY) {
+	if (ret) {
 		qxl_bo_unreserve(surf);
-		return -EBUSY;
+		return ret;
 	}
 
 	qxl_surface_evict_locked(qdev, surf, true);
diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c
index 4a0a8b2..a8dbb3e 100644
--- a/drivers/gpu/drm/qxl/qxl_display.c
+++ b/drivers/gpu/drm/qxl/qxl_display.c
@@ -67,7 +67,7 @@
 	crc = crc32(0, (const uint8_t *)&qdev->rom->client_monitors_config,
 		  sizeof(qdev->rom->client_monitors_config));
 	if (crc != qdev->rom->client_monitors_config_crc) {
-		qxl_io_log(qdev, "crc mismatch: have %X (%d) != %X\n", crc,
+		qxl_io_log(qdev, "crc mismatch: have %X (%zd) != %X\n", crc,
 			   sizeof(qdev->rom->client_monitors_config),
 			   qdev->rom->client_monitors_config_crc);
 		return 1;
diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h
index 7c6cafe..d854969 100644
--- a/drivers/gpu/drm/qxl/qxl_drv.h
+++ b/drivers/gpu/drm/qxl/qxl_drv.h
@@ -328,7 +328,7 @@
 };
 
 /* forward declaration for QXL_INFO_IO */
-void qxl_io_log(struct qxl_device *qdev, const char *fmt, ...);
+__printf(2,3) void qxl_io_log(struct qxl_device *qdev, const char *fmt, ...);
 
 extern const struct drm_ioctl_desc qxl_ioctls[];
 extern int qxl_max_ioctl;
diff --git a/drivers/gpu/drm/qxl/qxl_gem.c b/drivers/gpu/drm/qxl/qxl_gem.c
index b96f0c9..d9746e9 100644
--- a/drivers/gpu/drm/qxl/qxl_gem.c
+++ b/drivers/gpu/drm/qxl/qxl_gem.c
@@ -31,9 +31,15 @@
 void qxl_gem_object_free(struct drm_gem_object *gobj)
 {
 	struct qxl_bo *qobj = gem_to_qxl_bo(gobj);
+	struct qxl_device *qdev;
+	struct ttm_buffer_object *tbo;
 
-	if (qobj)
-		qxl_bo_unref(&qobj);
+	qdev = (struct qxl_device *)gobj->dev->dev_private;
+
+	qxl_surface_evict(qdev, qobj, false);
+
+	tbo = &qobj->tbo;
+	ttm_bo_unref(&tbo);
 }
 
 int qxl_gem_object_create(struct qxl_device *qdev, int size,
diff --git a/drivers/gpu/drm/qxl/qxl_ioctl.c b/drivers/gpu/drm/qxl/qxl_ioctl.c
index b110883..bda5c5f 100644
--- a/drivers/gpu/drm/qxl/qxl_ioctl.c
+++ b/drivers/gpu/drm/qxl/qxl_ioctl.c
@@ -107,9 +107,9 @@
 }
 
 /* return holding the reference to this object */
-static struct qxl_bo *qxlhw_handle_to_bo(struct qxl_device *qdev,
-					 struct drm_file *file_priv, uint64_t handle,
-					 struct qxl_release *release)
+static int qxlhw_handle_to_bo(struct qxl_device *qdev,
+			      struct drm_file *file_priv, uint64_t handle,
+			      struct qxl_release *release, struct qxl_bo **qbo_p)
 {
 	struct drm_gem_object *gobj;
 	struct qxl_bo *qobj;
@@ -117,15 +117,17 @@
 
 	gobj = drm_gem_object_lookup(qdev->ddev, file_priv, handle);
 	if (!gobj)
-		return NULL;
+		return -EINVAL;
 
 	qobj = gem_to_qxl_bo(gobj);
 
 	ret = qxl_release_list_add(release, qobj);
+	drm_gem_object_unreference_unlocked(gobj);
 	if (ret)
-		return NULL;
+		return ret;
 
-	return qobj;
+	*qbo_p = qobj;
+	return 0;
 }
 
 /*
@@ -143,7 +145,7 @@
 	struct qxl_release *release;
 	struct qxl_bo *cmd_bo;
 	void *fb_cmd;
-	int i, j, ret, num_relocs;
+	int i, ret, num_relocs;
 	int unwritten;
 
 	switch (cmd->type) {
@@ -210,7 +212,7 @@
 		/* add the bos to the list of bos to validate -
 		   need to validate first then process relocs? */
 		if (reloc.reloc_type != QXL_RELOC_TYPE_BO && reloc.reloc_type != QXL_RELOC_TYPE_SURF) {
-			DRM_DEBUG("unknown reloc type %d\n", reloc_info[i].type);
+			DRM_DEBUG("unknown reloc type %d\n", reloc.reloc_type);
 
 			ret = -EINVAL;
 			goto out_free_bos;
@@ -218,13 +220,10 @@
 		reloc_info[i].type = reloc.reloc_type;
 
 		if (reloc.dst_handle) {
-			reloc_info[i].dst_bo = qxlhw_handle_to_bo(qdev, file_priv,
-								  reloc.dst_handle, release);
-			if (!reloc_info[i].dst_bo) {
-				ret = -EINVAL;
-				reloc_info[i].src_bo = NULL;
+			ret = qxlhw_handle_to_bo(qdev, file_priv, reloc.dst_handle, release,
+						 &reloc_info[i].dst_bo);
+			if (ret)
 				goto out_free_bos;
-			}
 			reloc_info[i].dst_offset = reloc.dst_offset;
 		} else {
 			reloc_info[i].dst_bo = cmd_bo;
@@ -233,16 +232,11 @@
 		num_relocs++;
 
 		/* reserve and validate the reloc dst bo */
-		if (reloc.reloc_type == QXL_RELOC_TYPE_BO || reloc.src_handle > 0) {
-			reloc_info[i].src_bo =
-				qxlhw_handle_to_bo(qdev, file_priv,
-						   reloc.src_handle, release);
-			if (!reloc_info[i].src_bo) {
-				if (reloc_info[i].dst_bo != cmd_bo)
-					drm_gem_object_unreference_unlocked(&reloc_info[i].dst_bo->gem_base);
-				ret = -EINVAL;
+		if (reloc.reloc_type == QXL_RELOC_TYPE_BO || reloc.src_handle) {
+			ret = qxlhw_handle_to_bo(qdev, file_priv, reloc.src_handle, release,
+						 &reloc_info[i].src_bo);
+			if (ret)
 				goto out_free_bos;
-			}
 			reloc_info[i].src_offset = reloc.src_offset;
 		} else {
 			reloc_info[i].src_bo = NULL;
@@ -269,12 +263,6 @@
 		qxl_release_fence_buffer_objects(release);
 
 out_free_bos:
-	for (j = 0; j < num_relocs; j++) {
-		if (reloc_info[j].dst_bo != cmd_bo)
-			drm_gem_object_unreference_unlocked(&reloc_info[j].dst_bo->gem_base);
-		if (reloc_info[j].src_bo && reloc_info[j].src_bo != cmd_bo)
-			drm_gem_object_unreference_unlocked(&reloc_info[j].src_bo->gem_base);
-	}
 out_free_release:
 	if (ret)
 		qxl_release_free(qdev, release);
diff --git a/drivers/gpu/drm/qxl/qxl_object.c b/drivers/gpu/drm/qxl/qxl_object.c
index cdeaf08..6d6f33d 100644
--- a/drivers/gpu/drm/qxl/qxl_object.c
+++ b/drivers/gpu/drm/qxl/qxl_object.c
@@ -208,19 +208,16 @@
 
 void qxl_bo_unref(struct qxl_bo **bo)
 {
-	struct ttm_buffer_object *tbo;
-
 	if ((*bo) == NULL)
 		return;
-	tbo = &((*bo)->tbo);
-	ttm_bo_unref(&tbo);
-	if (tbo == NULL)
-		*bo = NULL;
+
+	drm_gem_object_unreference_unlocked(&(*bo)->gem_base);
+	*bo = NULL;
 }
 
 struct qxl_bo *qxl_bo_ref(struct qxl_bo *bo)
 {
-	ttm_bo_reference(&bo->tbo);
+	drm_gem_object_reference(&bo->gem_base);
 	return bo;
 }
 
diff --git a/drivers/gpu/drm/qxl/qxl_release.c b/drivers/gpu/drm/qxl/qxl_release.c
index d9b2568..b66ec33 100644
--- a/drivers/gpu/drm/qxl/qxl_release.c
+++ b/drivers/gpu/drm/qxl/qxl_release.c
@@ -122,7 +122,7 @@
 	.wait = qxl_fence_wait,
 };
 
-static uint64_t
+static int
 qxl_release_alloc(struct qxl_device *qdev, int type,
 		  struct qxl_release **ret)
 {
@@ -153,7 +153,7 @@
 		return handle;
 	}
 	*ret = release;
-	QXL_INFO(qdev, "allocated release %lld\n", handle);
+	QXL_INFO(qdev, "allocated release %d\n", handle);
 	release->id = handle;
 	return handle;
 }
@@ -363,6 +363,7 @@
 		ret = qxl_release_bo_alloc(qdev, &qdev->current_release_bo[cur_idx]);
 		if (ret) {
 			mutex_unlock(&qdev->release_mutex);
+			qxl_release_free(qdev, *release);
 			return ret;
 		}
 	}
@@ -377,13 +378,17 @@
 
 	mutex_unlock(&qdev->release_mutex);
 
-	qxl_release_list_add(*release, bo);
+	ret = qxl_release_list_add(*release, bo);
+	qxl_bo_unref(&bo);
+	if (ret) {
+		qxl_release_free(qdev, *release);
+		return ret;
+	}
 
 	info = qxl_release_map(qdev, *release);
 	info->id = idr_ret;
 	qxl_release_unmap(qdev, *release, info);
 
-	qxl_bo_unref(&bo);
 	return ret;
 }