cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

qxl_display.c (34959B)


      1/*
      2 * Copyright 2013 Red Hat Inc.
      3 *
      4 * Permission is hereby granted, free of charge, to any person obtaining a
      5 * copy of this software and associated documentation files (the "Software"),
      6 * to deal in the Software without restriction, including without limitation
      7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8 * and/or sell copies of the Software, and to permit persons to whom the
      9 * Software is furnished to do so, subject to the following conditions:
     10 *
     11 * The above copyright notice and this permission notice shall be included in
     12 * all copies or substantial portions of the Software.
     13 *
     14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     20 * OTHER DEALINGS IN THE SOFTWARE.
     21 *
     22 * Authors: Dave Airlie
     23 *          Alon Levy
     24 */
     25
     26#include <linux/crc32.h>
     27#include <linux/delay.h>
     28#include <linux/iosys-map.h>
     29
     30#include <drm/drm_drv.h>
     31#include <drm/drm_atomic.h>
     32#include <drm/drm_atomic_helper.h>
     33#include <drm/drm_gem_framebuffer_helper.h>
     34#include <drm/drm_plane_helper.h>
     35#include <drm/drm_probe_helper.h>
     36#include <drm/drm_simple_kms_helper.h>
     37#include <drm/drm_gem_atomic_helper.h>
     38
     39#include "qxl_drv.h"
     40#include "qxl_object.h"
     41
     42static bool qxl_head_enabled(struct qxl_head *head)
     43{
     44	return head->width && head->height;
     45}
     46
     47static int qxl_alloc_client_monitors_config(struct qxl_device *qdev,
     48		unsigned int count)
     49{
     50	if (qdev->client_monitors_config &&
     51	    count > qdev->client_monitors_config->count) {
     52		kfree(qdev->client_monitors_config);
     53		qdev->client_monitors_config = NULL;
     54	}
     55	if (!qdev->client_monitors_config) {
     56		qdev->client_monitors_config = kzalloc(
     57				struct_size(qdev->client_monitors_config,
     58				heads, count), GFP_KERNEL);
     59		if (!qdev->client_monitors_config)
     60			return -ENOMEM;
     61	}
     62	qdev->client_monitors_config->count = count;
     63	return 0;
     64}
     65
     66enum {
     67	MONITORS_CONFIG_MODIFIED,
     68	MONITORS_CONFIG_UNCHANGED,
     69	MONITORS_CONFIG_BAD_CRC,
     70	MONITORS_CONFIG_ERROR,
     71};
     72
     73static int qxl_display_copy_rom_client_monitors_config(struct qxl_device *qdev)
     74{
     75	int i;
     76	int num_monitors;
     77	uint32_t crc;
     78	int status = MONITORS_CONFIG_UNCHANGED;
     79
     80	num_monitors = qdev->rom->client_monitors_config.count;
     81	crc = crc32(0, (const uint8_t *)&qdev->rom->client_monitors_config,
     82		  sizeof(qdev->rom->client_monitors_config));
     83	if (crc != qdev->rom->client_monitors_config_crc)
     84		return MONITORS_CONFIG_BAD_CRC;
     85	if (!num_monitors) {
     86		DRM_DEBUG_KMS("no client monitors configured\n");
     87		return status;
     88	}
     89	if (num_monitors > qxl_num_crtc) {
     90		DRM_DEBUG_KMS("client monitors list will be truncated: %d < %d\n",
     91			      qxl_num_crtc, num_monitors);
     92		num_monitors = qxl_num_crtc;
     93	} else {
     94		num_monitors = qdev->rom->client_monitors_config.count;
     95	}
     96	if (qdev->client_monitors_config
     97	      && (num_monitors != qdev->client_monitors_config->count)) {
     98		status = MONITORS_CONFIG_MODIFIED;
     99	}
    100	if (qxl_alloc_client_monitors_config(qdev, num_monitors)) {
    101		status = MONITORS_CONFIG_ERROR;
    102		return status;
    103	}
    104	/* we copy max from the client but it isn't used */
    105	qdev->client_monitors_config->max_allowed = qxl_num_crtc;
    106	for (i = 0 ; i < qdev->client_monitors_config->count ; ++i) {
    107		struct qxl_urect *c_rect =
    108			&qdev->rom->client_monitors_config.heads[i];
    109		struct qxl_head *client_head =
    110			&qdev->client_monitors_config->heads[i];
    111		if (client_head->x != c_rect->left) {
    112			client_head->x = c_rect->left;
    113			status = MONITORS_CONFIG_MODIFIED;
    114		}
    115		if (client_head->y != c_rect->top) {
    116			client_head->y = c_rect->top;
    117			status = MONITORS_CONFIG_MODIFIED;
    118		}
    119		if (client_head->width != c_rect->right - c_rect->left) {
    120			client_head->width = c_rect->right - c_rect->left;
    121			status = MONITORS_CONFIG_MODIFIED;
    122		}
    123		if (client_head->height != c_rect->bottom - c_rect->top) {
    124			client_head->height = c_rect->bottom - c_rect->top;
    125			status = MONITORS_CONFIG_MODIFIED;
    126		}
    127		if (client_head->surface_id != 0) {
    128			client_head->surface_id = 0;
    129			status = MONITORS_CONFIG_MODIFIED;
    130		}
    131		if (client_head->id != i) {
    132			client_head->id = i;
    133			status = MONITORS_CONFIG_MODIFIED;
    134		}
    135		if (client_head->flags != 0) {
    136			client_head->flags = 0;
    137			status = MONITORS_CONFIG_MODIFIED;
    138		}
    139		DRM_DEBUG_KMS("read %dx%d+%d+%d\n", client_head->width, client_head->height,
    140			  client_head->x, client_head->y);
    141	}
    142
    143	return status;
    144}
    145
    146static void qxl_update_offset_props(struct qxl_device *qdev)
    147{
    148	struct drm_device *dev = &qdev->ddev;
    149	struct drm_connector *connector;
    150	struct qxl_output *output;
    151	struct qxl_head *head;
    152
    153	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
    154		output = drm_connector_to_qxl_output(connector);
    155
    156		head = &qdev->client_monitors_config->heads[output->index];
    157
    158		drm_object_property_set_value(&connector->base,
    159			dev->mode_config.suggested_x_property, head->x);
    160		drm_object_property_set_value(&connector->base,
    161			dev->mode_config.suggested_y_property, head->y);
    162	}
    163}
    164
    165void qxl_display_read_client_monitors_config(struct qxl_device *qdev)
    166{
    167	struct drm_device *dev = &qdev->ddev;
    168	struct drm_modeset_acquire_ctx ctx;
    169	int status, retries, ret;
    170
    171	for (retries = 0; retries < 10; retries++) {
    172		status = qxl_display_copy_rom_client_monitors_config(qdev);
    173		if (status != MONITORS_CONFIG_BAD_CRC)
    174			break;
    175		udelay(5);
    176	}
    177	if (status == MONITORS_CONFIG_ERROR) {
    178		DRM_DEBUG_KMS("ignoring client monitors config: error");
    179		return;
    180	}
    181	if (status == MONITORS_CONFIG_BAD_CRC) {
    182		DRM_DEBUG_KMS("ignoring client monitors config: bad crc");
    183		return;
    184	}
    185	if (status == MONITORS_CONFIG_UNCHANGED) {
    186		DRM_DEBUG_KMS("ignoring client monitors config: unchanged");
    187		return;
    188	}
    189
    190	DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE, ret);
    191	qxl_update_offset_props(qdev);
    192	DRM_MODESET_LOCK_ALL_END(dev, ctx, ret);
    193	if (!drm_helper_hpd_irq_event(dev)) {
    194		/* notify that the monitor configuration changed, to
    195		   adjust at the arbitrary resolution */
    196		drm_kms_helper_hotplug_event(dev);
    197	}
    198}
    199
    200static int qxl_check_mode(struct qxl_device *qdev,
    201			  unsigned int width,
    202			  unsigned int height)
    203{
    204	unsigned int stride;
    205	unsigned int size;
    206
    207	if (check_mul_overflow(width, 4u, &stride))
    208		return -EINVAL;
    209	if (check_mul_overflow(stride, height, &size))
    210		return -EINVAL;
    211	if (size > qdev->vram_size)
    212		return -ENOMEM;
    213	return 0;
    214}
    215
    216static int qxl_check_framebuffer(struct qxl_device *qdev,
    217				 struct qxl_bo *bo)
    218{
    219	return qxl_check_mode(qdev, bo->surf.width, bo->surf.height);
    220}
    221
    222static int qxl_add_mode(struct drm_connector *connector,
    223			unsigned int width,
    224			unsigned int height,
    225			bool preferred)
    226{
    227	struct drm_device *dev = connector->dev;
    228	struct qxl_device *qdev = to_qxl(dev);
    229	struct drm_display_mode *mode = NULL;
    230	int rc;
    231
    232	rc = qxl_check_mode(qdev, width, height);
    233	if (rc != 0)
    234		return 0;
    235
    236	mode = drm_cvt_mode(dev, width, height, 60, false, false, false);
    237	if (preferred)
    238		mode->type |= DRM_MODE_TYPE_PREFERRED;
    239	mode->hdisplay = width;
    240	mode->vdisplay = height;
    241	drm_mode_set_name(mode);
    242	drm_mode_probed_add(connector, mode);
    243	return 1;
    244}
    245
    246static int qxl_add_monitors_config_modes(struct drm_connector *connector)
    247{
    248	struct drm_device *dev = connector->dev;
    249	struct qxl_device *qdev = to_qxl(dev);
    250	struct qxl_output *output = drm_connector_to_qxl_output(connector);
    251	int h = output->index;
    252	struct qxl_head *head;
    253
    254	if (!qdev->monitors_config)
    255		return 0;
    256	if (h >= qxl_num_crtc)
    257		return 0;
    258	if (!qdev->client_monitors_config)
    259		return 0;
    260	if (h >= qdev->client_monitors_config->count)
    261		return 0;
    262
    263	head = &qdev->client_monitors_config->heads[h];
    264	DRM_DEBUG_KMS("head %d is %dx%d\n", h, head->width, head->height);
    265
    266	return qxl_add_mode(connector, head->width, head->height, true);
    267}
    268
    269static struct mode_size {
    270	int w;
    271	int h;
    272} extra_modes[] = {
    273	{ 720,  480},
    274	{1152,  768},
    275	{1280,  854},
    276};
    277
    278static int qxl_add_extra_modes(struct drm_connector *connector)
    279{
    280	int i, ret = 0;
    281
    282	for (i = 0; i < ARRAY_SIZE(extra_modes); i++)
    283		ret += qxl_add_mode(connector,
    284				    extra_modes[i].w,
    285				    extra_modes[i].h,
    286				    false);
    287	return ret;
    288}
    289
    290static void qxl_send_monitors_config(struct qxl_device *qdev)
    291{
    292	int i;
    293
    294	BUG_ON(!qdev->ram_header->monitors_config);
    295
    296	if (qdev->monitors_config->count == 0)
    297		return;
    298
    299	for (i = 0 ; i < qdev->monitors_config->count ; ++i) {
    300		struct qxl_head *head = &qdev->monitors_config->heads[i];
    301
    302		if (head->y > 8192 || head->x > 8192 ||
    303		    head->width > 8192 || head->height > 8192) {
    304			DRM_ERROR("head %d wrong: %dx%d+%d+%d\n",
    305				  i, head->width, head->height,
    306				  head->x, head->y);
    307			return;
    308		}
    309	}
    310	qxl_io_monitors_config(qdev);
    311}
    312
    313static void qxl_crtc_update_monitors_config(struct drm_crtc *crtc,
    314					    const char *reason)
    315{
    316	struct drm_device *dev = crtc->dev;
    317	struct qxl_device *qdev = to_qxl(dev);
    318	struct qxl_crtc *qcrtc = to_qxl_crtc(crtc);
    319	struct qxl_head head;
    320	int oldcount, i = qcrtc->index;
    321
    322	if (!qdev->primary_bo) {
    323		DRM_DEBUG_KMS("no primary surface, skip (%s)\n", reason);
    324		return;
    325	}
    326
    327	if (!qdev->monitors_config || qxl_num_crtc <= i)
    328		return;
    329
    330	head.id = i;
    331	head.flags = 0;
    332	head.surface_id = 0;
    333	oldcount = qdev->monitors_config->count;
    334	if (crtc->state->active) {
    335		struct drm_display_mode *mode = &crtc->mode;
    336
    337		head.width = mode->hdisplay;
    338		head.height = mode->vdisplay;
    339		head.x = crtc->x;
    340		head.y = crtc->y;
    341		if (qdev->monitors_config->count < i + 1)
    342			qdev->monitors_config->count = i + 1;
    343		if (qdev->primary_bo == qdev->dumb_shadow_bo)
    344			head.x += qdev->dumb_heads[i].x;
    345	} else if (i > 0) {
    346		head.width = 0;
    347		head.height = 0;
    348		head.x = 0;
    349		head.y = 0;
    350		if (qdev->monitors_config->count == i + 1)
    351			qdev->monitors_config->count = i;
    352	} else {
    353		DRM_DEBUG_KMS("inactive head 0, skip (%s)\n", reason);
    354		return;
    355	}
    356
    357	if (head.width  == qdev->monitors_config->heads[i].width  &&
    358	    head.height == qdev->monitors_config->heads[i].height &&
    359	    head.x      == qdev->monitors_config->heads[i].x      &&
    360	    head.y      == qdev->monitors_config->heads[i].y      &&
    361	    oldcount    == qdev->monitors_config->count)
    362		return;
    363
    364	DRM_DEBUG_KMS("head %d, %dx%d, at +%d+%d, %s (%s)\n",
    365		      i, head.width, head.height, head.x, head.y,
    366		      crtc->state->active ? "on" : "off", reason);
    367	if (oldcount != qdev->monitors_config->count)
    368		DRM_DEBUG_KMS("active heads %d -> %d (%d total)\n",
    369			      oldcount, qdev->monitors_config->count,
    370			      qxl_num_crtc);
    371
    372	qdev->monitors_config->heads[i] = head;
    373	qdev->monitors_config->max_allowed = qxl_num_crtc;
    374	qxl_send_monitors_config(qdev);
    375}
    376
    377static void qxl_crtc_atomic_flush(struct drm_crtc *crtc,
    378				  struct drm_atomic_state *state)
    379{
    380	qxl_crtc_update_monitors_config(crtc, "flush");
    381}
    382
    383static void qxl_crtc_destroy(struct drm_crtc *crtc)
    384{
    385	struct qxl_crtc *qxl_crtc = to_qxl_crtc(crtc);
    386
    387	qxl_bo_unref(&qxl_crtc->cursor_bo);
    388	drm_crtc_cleanup(crtc);
    389	kfree(qxl_crtc);
    390}
    391
    392static const struct drm_crtc_funcs qxl_crtc_funcs = {
    393	.set_config = drm_atomic_helper_set_config,
    394	.destroy = qxl_crtc_destroy,
    395	.page_flip = drm_atomic_helper_page_flip,
    396	.reset = drm_atomic_helper_crtc_reset,
    397	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
    398	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
    399};
    400
    401static int qxl_framebuffer_surface_dirty(struct drm_framebuffer *fb,
    402					 struct drm_file *file_priv,
    403					 unsigned int flags, unsigned int color,
    404					 struct drm_clip_rect *clips,
    405					 unsigned int num_clips)
    406{
    407	/* TODO: vmwgfx where this was cribbed from had locking. Why? */
    408	struct qxl_device *qdev = to_qxl(fb->dev);
    409	struct drm_clip_rect norect;
    410	struct qxl_bo *qobj;
    411	struct drm_modeset_acquire_ctx ctx;
    412	bool is_primary;
    413	int inc = 1, ret;
    414
    415	DRM_MODESET_LOCK_ALL_BEGIN(fb->dev, ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE, ret);
    416
    417	qobj = gem_to_qxl_bo(fb->obj[0]);
    418	/* if we aren't primary surface ignore this */
    419	is_primary = qobj->shadow ? qobj->shadow->is_primary : qobj->is_primary;
    420	if (!is_primary)
    421		goto out_lock_end;
    422
    423	if (!num_clips) {
    424		num_clips = 1;
    425		clips = &norect;
    426		norect.x1 = norect.y1 = 0;
    427		norect.x2 = fb->width;
    428		norect.y2 = fb->height;
    429	} else if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY) {
    430		num_clips /= 2;
    431		inc = 2; /* skip source rects */
    432	}
    433
    434	qxl_draw_dirty_fb(qdev, fb, qobj, flags, color,
    435			  clips, num_clips, inc, 0);
    436
    437out_lock_end:
    438	DRM_MODESET_LOCK_ALL_END(fb->dev, ctx, ret);
    439
    440	return 0;
    441}
    442
    443static const struct drm_framebuffer_funcs qxl_fb_funcs = {
    444	.destroy = drm_gem_fb_destroy,
    445	.dirty = qxl_framebuffer_surface_dirty,
    446	.create_handle = drm_gem_fb_create_handle,
    447};
    448
    449static void qxl_crtc_atomic_enable(struct drm_crtc *crtc,
    450				   struct drm_atomic_state *state)
    451{
    452	qxl_crtc_update_monitors_config(crtc, "enable");
    453}
    454
    455static void qxl_crtc_atomic_disable(struct drm_crtc *crtc,
    456				    struct drm_atomic_state *state)
    457{
    458	qxl_crtc_update_monitors_config(crtc, "disable");
    459}
    460
    461static const struct drm_crtc_helper_funcs qxl_crtc_helper_funcs = {
    462	.atomic_flush = qxl_crtc_atomic_flush,
    463	.atomic_enable = qxl_crtc_atomic_enable,
    464	.atomic_disable = qxl_crtc_atomic_disable,
    465};
    466
    467static int qxl_primary_atomic_check(struct drm_plane *plane,
    468				    struct drm_atomic_state *state)
    469{
    470	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
    471										 plane);
    472	struct qxl_device *qdev = to_qxl(plane->dev);
    473	struct qxl_bo *bo;
    474
    475	if (!new_plane_state->crtc || !new_plane_state->fb)
    476		return 0;
    477
    478	bo = gem_to_qxl_bo(new_plane_state->fb->obj[0]);
    479
    480	return qxl_check_framebuffer(qdev, bo);
    481}
    482
    483static int qxl_primary_apply_cursor(struct qxl_device *qdev,
    484				    struct drm_plane_state *plane_state)
    485{
    486	struct drm_framebuffer *fb = plane_state->fb;
    487	struct qxl_crtc *qcrtc = to_qxl_crtc(plane_state->crtc);
    488	struct qxl_cursor_cmd *cmd;
    489	struct qxl_release *release;
    490	int ret = 0;
    491
    492	if (!qcrtc->cursor_bo)
    493		return 0;
    494
    495	ret = qxl_alloc_release_reserved(qdev, sizeof(*cmd),
    496					 QXL_RELEASE_CURSOR_CMD,
    497					 &release, NULL);
    498	if (ret)
    499		return ret;
    500
    501	ret = qxl_release_list_add(release, qcrtc->cursor_bo);
    502	if (ret)
    503		goto out_free_release;
    504
    505	ret = qxl_release_reserve_list(release, false);
    506	if (ret)
    507		goto out_free_release;
    508
    509	cmd = (struct qxl_cursor_cmd *)qxl_release_map(qdev, release);
    510	cmd->type = QXL_CURSOR_SET;
    511	cmd->u.set.position.x = plane_state->crtc_x + fb->hot_x;
    512	cmd->u.set.position.y = plane_state->crtc_y + fb->hot_y;
    513
    514	cmd->u.set.shape = qxl_bo_physical_address(qdev, qcrtc->cursor_bo, 0);
    515
    516	cmd->u.set.visible = 1;
    517	qxl_release_unmap(qdev, release, &cmd->release_info);
    518
    519	qxl_release_fence_buffer_objects(release);
    520	qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
    521
    522	return ret;
    523
    524out_free_release:
    525	qxl_release_free(qdev, release);
    526	return ret;
    527}
    528
    529static int qxl_primary_move_cursor(struct qxl_device *qdev,
    530				   struct drm_plane_state *plane_state)
    531{
    532	struct drm_framebuffer *fb = plane_state->fb;
    533	struct qxl_crtc *qcrtc = to_qxl_crtc(plane_state->crtc);
    534	struct qxl_cursor_cmd *cmd;
    535	struct qxl_release *release;
    536	int ret = 0;
    537
    538	if (!qcrtc->cursor_bo)
    539		return 0;
    540
    541	ret = qxl_alloc_release_reserved(qdev, sizeof(*cmd),
    542					 QXL_RELEASE_CURSOR_CMD,
    543					 &release, NULL);
    544	if (ret)
    545		return ret;
    546
    547	ret = qxl_release_reserve_list(release, true);
    548	if (ret) {
    549		qxl_release_free(qdev, release);
    550		return ret;
    551	}
    552
    553	cmd = (struct qxl_cursor_cmd *)qxl_release_map(qdev, release);
    554	cmd->type = QXL_CURSOR_MOVE;
    555	cmd->u.position.x = plane_state->crtc_x + fb->hot_x;
    556	cmd->u.position.y = plane_state->crtc_y + fb->hot_y;
    557	qxl_release_unmap(qdev, release, &cmd->release_info);
    558
    559	qxl_release_fence_buffer_objects(release);
    560	qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
    561	return ret;
    562}
    563
    564static struct qxl_bo *qxl_create_cursor(struct qxl_device *qdev,
    565					struct qxl_bo *user_bo,
    566					int hot_x, int hot_y)
    567{
    568	static const u32 size = 64 * 64 * 4;
    569	struct qxl_bo *cursor_bo;
    570	struct iosys_map cursor_map;
    571	struct iosys_map user_map;
    572	struct qxl_cursor cursor;
    573	int ret;
    574
    575	if (!user_bo)
    576		return NULL;
    577
    578	ret = qxl_bo_create(qdev, sizeof(struct qxl_cursor) + size,
    579			    false, true, QXL_GEM_DOMAIN_VRAM, 1,
    580			    NULL, &cursor_bo);
    581	if (ret)
    582		goto err;
    583
    584	ret = qxl_bo_vmap(cursor_bo, &cursor_map);
    585	if (ret)
    586		goto err_unref;
    587
    588	ret = qxl_bo_vmap(user_bo, &user_map);
    589	if (ret)
    590		goto err_unmap;
    591
    592	cursor.header.unique = 0;
    593	cursor.header.type = SPICE_CURSOR_TYPE_ALPHA;
    594	cursor.header.width = 64;
    595	cursor.header.height = 64;
    596	cursor.header.hot_spot_x = hot_x;
    597	cursor.header.hot_spot_y = hot_y;
    598	cursor.data_size = size;
    599	cursor.chunk.next_chunk = 0;
    600	cursor.chunk.prev_chunk = 0;
    601	cursor.chunk.data_size = size;
    602	if (cursor_map.is_iomem) {
    603		memcpy_toio(cursor_map.vaddr_iomem,
    604			    &cursor, sizeof(cursor));
    605		memcpy_toio(cursor_map.vaddr_iomem + sizeof(cursor),
    606			    user_map.vaddr, size);
    607	} else {
    608		memcpy(cursor_map.vaddr,
    609		       &cursor, sizeof(cursor));
    610		memcpy(cursor_map.vaddr + sizeof(cursor),
    611		       user_map.vaddr, size);
    612	}
    613
    614	qxl_bo_vunmap(user_bo);
    615	qxl_bo_vunmap(cursor_bo);
    616	return cursor_bo;
    617
    618err_unmap:
    619	qxl_bo_vunmap(cursor_bo);
    620err_unref:
    621	qxl_bo_unpin(cursor_bo);
    622	qxl_bo_unref(&cursor_bo);
    623err:
    624	return NULL;
    625}
    626
    627static void qxl_free_cursor(struct qxl_bo *cursor_bo)
    628{
    629	if (!cursor_bo)
    630		return;
    631
    632	qxl_bo_unpin(cursor_bo);
    633	qxl_bo_unref(&cursor_bo);
    634}
    635
    636static void qxl_primary_atomic_update(struct drm_plane *plane,
    637				      struct drm_atomic_state *state)
    638{
    639	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
    640									   plane);
    641	struct qxl_device *qdev = to_qxl(plane->dev);
    642	struct qxl_bo *bo = gem_to_qxl_bo(new_state->fb->obj[0]);
    643	struct qxl_bo *primary;
    644	struct drm_clip_rect norect = {
    645	    .x1 = 0,
    646	    .y1 = 0,
    647	    .x2 = new_state->fb->width,
    648	    .y2 = new_state->fb->height
    649	};
    650	uint32_t dumb_shadow_offset = 0;
    651
    652	primary = bo->shadow ? bo->shadow : bo;
    653
    654	if (!primary->is_primary) {
    655		if (qdev->primary_bo)
    656			qxl_io_destroy_primary(qdev);
    657		qxl_io_create_primary(qdev, primary);
    658		qxl_primary_apply_cursor(qdev, plane->state);
    659	}
    660
    661	if (bo->is_dumb)
    662		dumb_shadow_offset =
    663			qdev->dumb_heads[new_state->crtc->index].x;
    664
    665	qxl_draw_dirty_fb(qdev, new_state->fb, bo, 0, 0, &norect, 1, 1,
    666			  dumb_shadow_offset);
    667}
    668
    669static void qxl_primary_atomic_disable(struct drm_plane *plane,
    670				       struct drm_atomic_state *state)
    671{
    672	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
    673									   plane);
    674	struct qxl_device *qdev = to_qxl(plane->dev);
    675
    676	if (old_state->fb) {
    677		struct qxl_bo *bo = gem_to_qxl_bo(old_state->fb->obj[0]);
    678
    679		if (bo->shadow)
    680			bo = bo->shadow;
    681		if (bo->is_primary)
    682			qxl_io_destroy_primary(qdev);
    683	}
    684}
    685
    686static void qxl_cursor_atomic_update(struct drm_plane *plane,
    687				     struct drm_atomic_state *state)
    688{
    689	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
    690									   plane);
    691	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
    692									   plane);
    693	struct qxl_device *qdev = to_qxl(plane->dev);
    694	struct drm_framebuffer *fb = new_state->fb;
    695
    696	if (fb != old_state->fb) {
    697		qxl_primary_apply_cursor(qdev, new_state);
    698	} else {
    699		qxl_primary_move_cursor(qdev, new_state);
    700	}
    701}
    702
    703static void qxl_cursor_atomic_disable(struct drm_plane *plane,
    704				      struct drm_atomic_state *state)
    705{
    706	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
    707									   plane);
    708	struct qxl_device *qdev = to_qxl(plane->dev);
    709	struct qxl_crtc *qcrtc;
    710	struct qxl_release *release;
    711	struct qxl_cursor_cmd *cmd;
    712	int ret;
    713
    714	ret = qxl_alloc_release_reserved(qdev, sizeof(*cmd),
    715					 QXL_RELEASE_CURSOR_CMD,
    716					 &release, NULL);
    717	if (ret)
    718		return;
    719
    720	ret = qxl_release_reserve_list(release, true);
    721	if (ret) {
    722		qxl_release_free(qdev, release);
    723		return;
    724	}
    725
    726	cmd = (struct qxl_cursor_cmd *)qxl_release_map(qdev, release);
    727	cmd->type = QXL_CURSOR_HIDE;
    728	qxl_release_unmap(qdev, release, &cmd->release_info);
    729
    730	qxl_release_fence_buffer_objects(release);
    731	qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
    732
    733	qcrtc = to_qxl_crtc(old_state->crtc);
    734	qxl_free_cursor(qcrtc->cursor_bo);
    735	qcrtc->cursor_bo = NULL;
    736}
    737
    738static void qxl_update_dumb_head(struct qxl_device *qdev,
    739				 int index, struct qxl_bo *bo)
    740{
    741	uint32_t width, height;
    742
    743	if (index >= qdev->monitors_config->max_allowed)
    744		return;
    745
    746	if (bo && bo->is_dumb) {
    747		width = bo->surf.width;
    748		height = bo->surf.height;
    749	} else {
    750		width = 0;
    751		height = 0;
    752	}
    753
    754	if (qdev->dumb_heads[index].width == width &&
    755	    qdev->dumb_heads[index].height == height)
    756		return;
    757
    758	DRM_DEBUG("#%d: %dx%d -> %dx%d\n", index,
    759		  qdev->dumb_heads[index].width,
    760		  qdev->dumb_heads[index].height,
    761		  width, height);
    762	qdev->dumb_heads[index].width = width;
    763	qdev->dumb_heads[index].height = height;
    764}
    765
    766static void qxl_calc_dumb_shadow(struct qxl_device *qdev,
    767				 struct qxl_surface *surf)
    768{
    769	struct qxl_head *head;
    770	int i;
    771
    772	memset(surf, 0, sizeof(*surf));
    773	for (i = 0; i < qdev->monitors_config->max_allowed; i++) {
    774		head = qdev->dumb_heads + i;
    775		head->x = surf->width;
    776		surf->width += head->width;
    777		if (surf->height < head->height)
    778			surf->height = head->height;
    779	}
    780	if (surf->width < 64)
    781		surf->width = 64;
    782	if (surf->height < 64)
    783		surf->height = 64;
    784	surf->format = SPICE_SURFACE_FMT_32_xRGB;
    785	surf->stride = surf->width * 4;
    786
    787	if (!qdev->dumb_shadow_bo ||
    788	    qdev->dumb_shadow_bo->surf.width != surf->width ||
    789	    qdev->dumb_shadow_bo->surf.height != surf->height)
    790		DRM_DEBUG("%dx%d\n", surf->width, surf->height);
    791}
    792
    793static void qxl_prepare_shadow(struct qxl_device *qdev, struct qxl_bo *user_bo,
    794			       int crtc_index)
    795{
    796	struct qxl_surface surf;
    797
    798	qxl_update_dumb_head(qdev, crtc_index,
    799			     user_bo);
    800	qxl_calc_dumb_shadow(qdev, &surf);
    801	if (!qdev->dumb_shadow_bo ||
    802	    qdev->dumb_shadow_bo->surf.width  != surf.width ||
    803	    qdev->dumb_shadow_bo->surf.height != surf.height) {
    804		if (qdev->dumb_shadow_bo) {
    805			qxl_bo_unpin(qdev->dumb_shadow_bo);
    806			drm_gem_object_put
    807				(&qdev->dumb_shadow_bo->tbo.base);
    808			qdev->dumb_shadow_bo = NULL;
    809		}
    810		qxl_bo_create(qdev, surf.height * surf.stride,
    811			      true, true, QXL_GEM_DOMAIN_SURFACE, 0,
    812			      &surf, &qdev->dumb_shadow_bo);
    813	}
    814	if (user_bo->shadow != qdev->dumb_shadow_bo) {
    815		if (user_bo->shadow) {
    816			qxl_bo_unpin(user_bo->shadow);
    817			drm_gem_object_put
    818				(&user_bo->shadow->tbo.base);
    819			user_bo->shadow = NULL;
    820		}
    821		drm_gem_object_get(&qdev->dumb_shadow_bo->tbo.base);
    822		user_bo->shadow = qdev->dumb_shadow_bo;
    823		qxl_bo_pin(user_bo->shadow);
    824	}
    825}
    826
    827static int qxl_plane_prepare_fb(struct drm_plane *plane,
    828				struct drm_plane_state *new_state)
    829{
    830	struct qxl_device *qdev = to_qxl(plane->dev);
    831	struct drm_gem_object *obj;
    832	struct qxl_bo *user_bo;
    833	int ret;
    834
    835	if (!new_state->fb)
    836		return 0;
    837
    838	obj = new_state->fb->obj[0];
    839	user_bo = gem_to_qxl_bo(obj);
    840
    841	if (plane->type == DRM_PLANE_TYPE_PRIMARY &&
    842	    user_bo->is_dumb) {
    843		qxl_prepare_shadow(qdev, user_bo, new_state->crtc->index);
    844	}
    845
    846	if (plane->type == DRM_PLANE_TYPE_CURSOR &&
    847	    plane->state->fb != new_state->fb) {
    848		struct qxl_crtc *qcrtc = to_qxl_crtc(new_state->crtc);
    849		struct qxl_bo *old_cursor_bo = qcrtc->cursor_bo;
    850
    851		qcrtc->cursor_bo = qxl_create_cursor(qdev, user_bo,
    852						     new_state->fb->hot_x,
    853						     new_state->fb->hot_y);
    854		qxl_free_cursor(old_cursor_bo);
    855	}
    856
    857	ret = qxl_bo_pin(user_bo);
    858	if (ret)
    859		return ret;
    860
    861	return drm_gem_plane_helper_prepare_fb(plane, new_state);
    862}
    863
    864static void qxl_plane_cleanup_fb(struct drm_plane *plane,
    865				 struct drm_plane_state *old_state)
    866{
    867	struct drm_gem_object *obj;
    868	struct qxl_bo *user_bo;
    869
    870	if (!old_state->fb) {
    871		/*
    872		 * we never executed prepare_fb, so there's nothing to
    873		 * unpin.
    874		 */
    875		return;
    876	}
    877
    878	obj = old_state->fb->obj[0];
    879	user_bo = gem_to_qxl_bo(obj);
    880	qxl_bo_unpin(user_bo);
    881
    882	if (old_state->fb != plane->state->fb && user_bo->shadow) {
    883		qxl_bo_unpin(user_bo->shadow);
    884		drm_gem_object_put(&user_bo->shadow->tbo.base);
    885		user_bo->shadow = NULL;
    886	}
    887}
    888
    889static const uint32_t qxl_cursor_plane_formats[] = {
    890	DRM_FORMAT_ARGB8888,
    891};
    892
    893static const struct drm_plane_helper_funcs qxl_cursor_helper_funcs = {
    894	.atomic_update = qxl_cursor_atomic_update,
    895	.atomic_disable = qxl_cursor_atomic_disable,
    896	.prepare_fb = qxl_plane_prepare_fb,
    897	.cleanup_fb = qxl_plane_cleanup_fb,
    898};
    899
    900static const struct drm_plane_funcs qxl_cursor_plane_funcs = {
    901	.update_plane	= drm_atomic_helper_update_plane,
    902	.disable_plane	= drm_atomic_helper_disable_plane,
    903	.destroy	= drm_primary_helper_destroy,
    904	.reset		= drm_atomic_helper_plane_reset,
    905	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
    906	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
    907};
    908
    909static const uint32_t qxl_primary_plane_formats[] = {
    910	DRM_FORMAT_XRGB8888,
    911	DRM_FORMAT_ARGB8888,
    912};
    913
    914static const struct drm_plane_helper_funcs primary_helper_funcs = {
    915	.atomic_check = qxl_primary_atomic_check,
    916	.atomic_update = qxl_primary_atomic_update,
    917	.atomic_disable = qxl_primary_atomic_disable,
    918	.prepare_fb = qxl_plane_prepare_fb,
    919	.cleanup_fb = qxl_plane_cleanup_fb,
    920};
    921
    922static const struct drm_plane_funcs qxl_primary_plane_funcs = {
    923	.update_plane	= drm_atomic_helper_update_plane,
    924	.disable_plane	= drm_atomic_helper_disable_plane,
    925	.destroy	= drm_primary_helper_destroy,
    926	.reset		= drm_atomic_helper_plane_reset,
    927	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
    928	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
    929};
    930
    931static struct drm_plane *qxl_create_plane(struct qxl_device *qdev,
    932					  unsigned int possible_crtcs,
    933					  enum drm_plane_type type)
    934{
    935	const struct drm_plane_helper_funcs *helper_funcs = NULL;
    936	struct drm_plane *plane;
    937	const struct drm_plane_funcs *funcs;
    938	const uint32_t *formats;
    939	int num_formats;
    940	int err;
    941
    942	if (type == DRM_PLANE_TYPE_PRIMARY) {
    943		funcs = &qxl_primary_plane_funcs;
    944		formats = qxl_primary_plane_formats;
    945		num_formats = ARRAY_SIZE(qxl_primary_plane_formats);
    946		helper_funcs = &primary_helper_funcs;
    947	} else if (type == DRM_PLANE_TYPE_CURSOR) {
    948		funcs = &qxl_cursor_plane_funcs;
    949		formats = qxl_cursor_plane_formats;
    950		helper_funcs = &qxl_cursor_helper_funcs;
    951		num_formats = ARRAY_SIZE(qxl_cursor_plane_formats);
    952	} else {
    953		return ERR_PTR(-EINVAL);
    954	}
    955
    956	plane = kzalloc(sizeof(*plane), GFP_KERNEL);
    957	if (!plane)
    958		return ERR_PTR(-ENOMEM);
    959
    960	err = drm_universal_plane_init(&qdev->ddev, plane, possible_crtcs,
    961				       funcs, formats, num_formats,
    962				       NULL, type, NULL);
    963	if (err)
    964		goto free_plane;
    965
    966	drm_plane_helper_add(plane, helper_funcs);
    967
    968	return plane;
    969
    970free_plane:
    971	kfree(plane);
    972	return ERR_PTR(-EINVAL);
    973}
    974
    975static int qdev_crtc_init(struct drm_device *dev, int crtc_id)
    976{
    977	struct qxl_crtc *qxl_crtc;
    978	struct drm_plane *primary, *cursor;
    979	struct qxl_device *qdev = to_qxl(dev);
    980	int r;
    981
    982	qxl_crtc = kzalloc(sizeof(struct qxl_crtc), GFP_KERNEL);
    983	if (!qxl_crtc)
    984		return -ENOMEM;
    985
    986	primary = qxl_create_plane(qdev, 1 << crtc_id, DRM_PLANE_TYPE_PRIMARY);
    987	if (IS_ERR(primary)) {
    988		r = -ENOMEM;
    989		goto free_mem;
    990	}
    991
    992	cursor = qxl_create_plane(qdev, 1 << crtc_id, DRM_PLANE_TYPE_CURSOR);
    993	if (IS_ERR(cursor)) {
    994		r = -ENOMEM;
    995		goto clean_primary;
    996	}
    997
    998	r = drm_crtc_init_with_planes(dev, &qxl_crtc->base, primary, cursor,
    999				      &qxl_crtc_funcs, NULL);
   1000	if (r)
   1001		goto clean_cursor;
   1002
   1003	qxl_crtc->index = crtc_id;
   1004	drm_crtc_helper_add(&qxl_crtc->base, &qxl_crtc_helper_funcs);
   1005	return 0;
   1006
   1007clean_cursor:
   1008	drm_plane_cleanup(cursor);
   1009	kfree(cursor);
   1010clean_primary:
   1011	drm_plane_cleanup(primary);
   1012	kfree(primary);
   1013free_mem:
   1014	kfree(qxl_crtc);
   1015	return r;
   1016}
   1017
   1018static int qxl_conn_get_modes(struct drm_connector *connector)
   1019{
   1020	struct drm_device *dev = connector->dev;
   1021	struct qxl_device *qdev = to_qxl(dev);
   1022	struct qxl_output *output = drm_connector_to_qxl_output(connector);
   1023	unsigned int pwidth = 1024;
   1024	unsigned int pheight = 768;
   1025	int ret = 0;
   1026
   1027	if (qdev->client_monitors_config) {
   1028		struct qxl_head *head;
   1029		head = &qdev->client_monitors_config->heads[output->index];
   1030		if (head->width)
   1031			pwidth = head->width;
   1032		if (head->height)
   1033			pheight = head->height;
   1034	}
   1035
   1036	ret += drm_add_modes_noedid(connector, 8192, 8192);
   1037	ret += qxl_add_extra_modes(connector);
   1038	ret += qxl_add_monitors_config_modes(connector);
   1039	drm_set_preferred_mode(connector, pwidth, pheight);
   1040	return ret;
   1041}
   1042
   1043static enum drm_mode_status qxl_conn_mode_valid(struct drm_connector *connector,
   1044			       struct drm_display_mode *mode)
   1045{
   1046	struct drm_device *ddev = connector->dev;
   1047	struct qxl_device *qdev = to_qxl(ddev);
   1048
   1049	if (qxl_check_mode(qdev, mode->hdisplay, mode->vdisplay) != 0)
   1050		return MODE_BAD;
   1051
   1052	return MODE_OK;
   1053}
   1054
   1055static struct drm_encoder *qxl_best_encoder(struct drm_connector *connector)
   1056{
   1057	struct qxl_output *qxl_output =
   1058		drm_connector_to_qxl_output(connector);
   1059
   1060	DRM_DEBUG("\n");
   1061	return &qxl_output->enc;
   1062}
   1063
   1064static const struct drm_connector_helper_funcs qxl_connector_helper_funcs = {
   1065	.get_modes = qxl_conn_get_modes,
   1066	.mode_valid = qxl_conn_mode_valid,
   1067	.best_encoder = qxl_best_encoder,
   1068};
   1069
   1070static enum drm_connector_status qxl_conn_detect(
   1071			struct drm_connector *connector,
   1072			bool force)
   1073{
   1074	struct qxl_output *output =
   1075		drm_connector_to_qxl_output(connector);
   1076	struct drm_device *ddev = connector->dev;
   1077	struct qxl_device *qdev = to_qxl(ddev);
   1078	bool connected = false;
   1079
   1080	/* The first monitor is always connected */
   1081	if (!qdev->client_monitors_config) {
   1082		if (output->index == 0)
   1083			connected = true;
   1084	} else
   1085		connected = qdev->client_monitors_config->count > output->index &&
   1086		     qxl_head_enabled(&qdev->client_monitors_config->heads[output->index]);
   1087
   1088	DRM_DEBUG("#%d connected: %d\n", output->index, connected);
   1089
   1090	return connected ? connector_status_connected
   1091			 : connector_status_disconnected;
   1092}
   1093
   1094static void qxl_conn_destroy(struct drm_connector *connector)
   1095{
   1096	struct qxl_output *qxl_output =
   1097		drm_connector_to_qxl_output(connector);
   1098
   1099	drm_connector_unregister(connector);
   1100	drm_connector_cleanup(connector);
   1101	kfree(qxl_output);
   1102}
   1103
   1104static const struct drm_connector_funcs qxl_connector_funcs = {
   1105	.detect = qxl_conn_detect,
   1106	.fill_modes = drm_helper_probe_single_connector_modes,
   1107	.destroy = qxl_conn_destroy,
   1108	.reset = drm_atomic_helper_connector_reset,
   1109	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
   1110	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
   1111};
   1112
   1113static int qxl_mode_create_hotplug_mode_update_property(struct qxl_device *qdev)
   1114{
   1115	if (qdev->hotplug_mode_update_property)
   1116		return 0;
   1117
   1118	qdev->hotplug_mode_update_property =
   1119		drm_property_create_range(&qdev->ddev, DRM_MODE_PROP_IMMUTABLE,
   1120					  "hotplug_mode_update", 0, 1);
   1121
   1122	return 0;
   1123}
   1124
   1125static int qdev_output_init(struct drm_device *dev, int num_output)
   1126{
   1127	struct qxl_device *qdev = to_qxl(dev);
   1128	struct qxl_output *qxl_output;
   1129	struct drm_connector *connector;
   1130	struct drm_encoder *encoder;
   1131	int ret;
   1132
   1133	qxl_output = kzalloc(sizeof(struct qxl_output), GFP_KERNEL);
   1134	if (!qxl_output)
   1135		return -ENOMEM;
   1136
   1137	qxl_output->index = num_output;
   1138
   1139	connector = &qxl_output->base;
   1140	encoder = &qxl_output->enc;
   1141	drm_connector_init(dev, &qxl_output->base,
   1142			   &qxl_connector_funcs, DRM_MODE_CONNECTOR_VIRTUAL);
   1143
   1144	ret = drm_simple_encoder_init(dev, &qxl_output->enc,
   1145				      DRM_MODE_ENCODER_VIRTUAL);
   1146	if (ret) {
   1147		drm_err(dev, "drm_simple_encoder_init() failed, error %d\n",
   1148			ret);
   1149		goto err_drm_connector_cleanup;
   1150	}
   1151
   1152	/* we get HPD via client monitors config */
   1153	connector->polled = DRM_CONNECTOR_POLL_HPD;
   1154	encoder->possible_crtcs = 1 << num_output;
   1155	drm_connector_attach_encoder(&qxl_output->base,
   1156					  &qxl_output->enc);
   1157	drm_connector_helper_add(connector, &qxl_connector_helper_funcs);
   1158
   1159	drm_object_attach_property(&connector->base,
   1160				   qdev->hotplug_mode_update_property, 0);
   1161	drm_object_attach_property(&connector->base,
   1162				   dev->mode_config.suggested_x_property, 0);
   1163	drm_object_attach_property(&connector->base,
   1164				   dev->mode_config.suggested_y_property, 0);
   1165	return 0;
   1166
   1167err_drm_connector_cleanup:
   1168	drm_connector_cleanup(&qxl_output->base);
   1169	kfree(qxl_output);
   1170	return ret;
   1171}
   1172
   1173static struct drm_framebuffer *
   1174qxl_user_framebuffer_create(struct drm_device *dev,
   1175			    struct drm_file *file_priv,
   1176			    const struct drm_mode_fb_cmd2 *mode_cmd)
   1177{
   1178	return drm_gem_fb_create_with_funcs(dev, file_priv, mode_cmd,
   1179					    &qxl_fb_funcs);
   1180}
   1181
   1182static const struct drm_mode_config_funcs qxl_mode_funcs = {
   1183	.fb_create = qxl_user_framebuffer_create,
   1184	.atomic_check = drm_atomic_helper_check,
   1185	.atomic_commit = drm_atomic_helper_commit,
   1186};
   1187
   1188int qxl_create_monitors_object(struct qxl_device *qdev)
   1189{
   1190	int ret;
   1191	struct drm_gem_object *gobj;
   1192	struct iosys_map map;
   1193	int monitors_config_size = sizeof(struct qxl_monitors_config) +
   1194		qxl_num_crtc * sizeof(struct qxl_head);
   1195
   1196	ret = qxl_gem_object_create(qdev, monitors_config_size, 0,
   1197				    QXL_GEM_DOMAIN_VRAM,
   1198				    false, false, NULL, &gobj);
   1199	if (ret) {
   1200		DRM_ERROR("%s: failed to create gem ret=%d\n", __func__, ret);
   1201		return -ENOMEM;
   1202	}
   1203	qdev->monitors_config_bo = gem_to_qxl_bo(gobj);
   1204
   1205	ret = qxl_bo_vmap(qdev->monitors_config_bo, &map);
   1206	if (ret)
   1207		return ret;
   1208
   1209	qdev->monitors_config = qdev->monitors_config_bo->kptr;
   1210	qdev->ram_header->monitors_config =
   1211		qxl_bo_physical_address(qdev, qdev->monitors_config_bo, 0);
   1212
   1213	memset(qdev->monitors_config, 0, monitors_config_size);
   1214	qdev->dumb_heads = kcalloc(qxl_num_crtc, sizeof(qdev->dumb_heads[0]),
   1215				   GFP_KERNEL);
   1216	if (!qdev->dumb_heads) {
   1217		qxl_destroy_monitors_object(qdev);
   1218		return -ENOMEM;
   1219	}
   1220	return 0;
   1221}
   1222
   1223int qxl_destroy_monitors_object(struct qxl_device *qdev)
   1224{
   1225	int ret;
   1226
   1227	if (!qdev->monitors_config_bo)
   1228		return 0;
   1229
   1230	qdev->monitors_config = NULL;
   1231	qdev->ram_header->monitors_config = 0;
   1232
   1233	ret = qxl_bo_vunmap(qdev->monitors_config_bo);
   1234	if (ret)
   1235		return ret;
   1236
   1237	qxl_bo_unref(&qdev->monitors_config_bo);
   1238	return 0;
   1239}
   1240
   1241int qxl_modeset_init(struct qxl_device *qdev)
   1242{
   1243	int i;
   1244	int ret;
   1245
   1246	ret = drmm_mode_config_init(&qdev->ddev);
   1247	if (ret)
   1248		return ret;
   1249
   1250	ret = qxl_create_monitors_object(qdev);
   1251	if (ret)
   1252		return ret;
   1253
   1254	qdev->ddev.mode_config.funcs = (void *)&qxl_mode_funcs;
   1255
   1256	/* modes will be validated against the framebuffer size */
   1257	qdev->ddev.mode_config.min_width = 0;
   1258	qdev->ddev.mode_config.min_height = 0;
   1259	qdev->ddev.mode_config.max_width = 8192;
   1260	qdev->ddev.mode_config.max_height = 8192;
   1261
   1262	qdev->ddev.mode_config.fb_base = qdev->vram_base;
   1263
   1264	drm_mode_create_suggested_offset_properties(&qdev->ddev);
   1265	qxl_mode_create_hotplug_mode_update_property(qdev);
   1266
   1267	for (i = 0 ; i < qxl_num_crtc; ++i) {
   1268		qdev_crtc_init(&qdev->ddev, i);
   1269		qdev_output_init(&qdev->ddev, i);
   1270	}
   1271
   1272	qxl_display_read_client_monitors_config(qdev);
   1273
   1274	drm_mode_config_reset(&qdev->ddev);
   1275	return 0;
   1276}
   1277
   1278void qxl_modeset_fini(struct qxl_device *qdev)
   1279{
   1280	if (qdev->dumb_shadow_bo) {
   1281		qxl_bo_unpin(qdev->dumb_shadow_bo);
   1282		drm_gem_object_put(&qdev->dumb_shadow_bo->tbo.base);
   1283		qdev->dumb_shadow_bo = NULL;
   1284	}
   1285	qxl_destroy_monitors_object(qdev);
   1286}