brintos

brintos / linux-shallow public Read only

0
0
Text · 20.0 KiB · aab79c5 Raw
796 lines · c
1// SPDX-License-Identifier: GPL-2.0 OR MIT2 3/*4 *  Xen para-virtual DRM device5 *6 * Copyright (C) 2016-2018 EPAM Systems Inc.7 *8 * Author: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>9 */10 11#include <linux/delay.h>12#include <linux/dma-mapping.h>13#include <linux/module.h>14 15#include <drm/drm_atomic_helper.h>16#include <drm/drm_drv.h>17#include <drm/drm_ioctl.h>18#include <drm/drm_probe_helper.h>19#include <drm/drm_file.h>20#include <drm/drm_gem.h>21 22#include <xen/platform_pci.h>23#include <xen/xen.h>24#include <xen/xenbus.h>25 26#include <xen/xen-front-pgdir-shbuf.h>27#include <xen/interface/io/displif.h>28 29#include "xen_drm_front.h"30#include "xen_drm_front_cfg.h"31#include "xen_drm_front_evtchnl.h"32#include "xen_drm_front_gem.h"33#include "xen_drm_front_kms.h"34 35struct xen_drm_front_dbuf {36	struct list_head list;37	u64 dbuf_cookie;38	u64 fb_cookie;39 40	struct xen_front_pgdir_shbuf shbuf;41};42 43static void dbuf_add_to_list(struct xen_drm_front_info *front_info,44			     struct xen_drm_front_dbuf *dbuf, u64 dbuf_cookie)45{46	dbuf->dbuf_cookie = dbuf_cookie;47	list_add(&dbuf->list, &front_info->dbuf_list);48}49 50static struct xen_drm_front_dbuf *dbuf_get(struct list_head *dbuf_list,51					   u64 dbuf_cookie)52{53	struct xen_drm_front_dbuf *buf, *q;54 55	list_for_each_entry_safe(buf, q, dbuf_list, list)56		if (buf->dbuf_cookie == dbuf_cookie)57			return buf;58 59	return NULL;60}61 62static void dbuf_free(struct list_head *dbuf_list, u64 dbuf_cookie)63{64	struct xen_drm_front_dbuf *buf, *q;65 66	list_for_each_entry_safe(buf, q, dbuf_list, list)67		if (buf->dbuf_cookie == dbuf_cookie) {68			list_del(&buf->list);69			xen_front_pgdir_shbuf_unmap(&buf->shbuf);70			xen_front_pgdir_shbuf_free(&buf->shbuf);71			kfree(buf);72			break;73		}74}75 76static void dbuf_free_all(struct list_head *dbuf_list)77{78	struct xen_drm_front_dbuf *buf, *q;79 80	list_for_each_entry_safe(buf, q, dbuf_list, list) {81		list_del(&buf->list);82		xen_front_pgdir_shbuf_unmap(&buf->shbuf);83		xen_front_pgdir_shbuf_free(&buf->shbuf);84		kfree(buf);85	}86}87 88static struct xendispl_req *89be_prepare_req(struct xen_drm_front_evtchnl *evtchnl, u8 operation)90{91	struct xendispl_req *req;92 93	req = RING_GET_REQUEST(&evtchnl->u.req.ring,94			       evtchnl->u.req.ring.req_prod_pvt);95	req->operation = operation;96	req->id = evtchnl->evt_next_id++;97	evtchnl->evt_id = req->id;98	return req;99}100 101static int be_stream_do_io(struct xen_drm_front_evtchnl *evtchnl,102			   struct xendispl_req *req)103{104	reinit_completion(&evtchnl->u.req.completion);105	if (unlikely(evtchnl->state != EVTCHNL_STATE_CONNECTED))106		return -EIO;107 108	xen_drm_front_evtchnl_flush(evtchnl);109	return 0;110}111 112static int be_stream_wait_io(struct xen_drm_front_evtchnl *evtchnl)113{114	if (wait_for_completion_timeout(&evtchnl->u.req.completion,115			msecs_to_jiffies(XEN_DRM_FRONT_WAIT_BACK_MS)) <= 0)116		return -ETIMEDOUT;117 118	return evtchnl->u.req.resp_status;119}120 121int xen_drm_front_mode_set(struct xen_drm_front_drm_pipeline *pipeline,122			   u32 x, u32 y, u32 width, u32 height,123			   u32 bpp, u64 fb_cookie)124{125	struct xen_drm_front_evtchnl *evtchnl;126	struct xen_drm_front_info *front_info;127	struct xendispl_req *req;128	unsigned long flags;129	int ret;130 131	front_info = pipeline->drm_info->front_info;132	evtchnl = &front_info->evt_pairs[pipeline->index].req;133	if (unlikely(!evtchnl))134		return -EIO;135 136	mutex_lock(&evtchnl->u.req.req_io_lock);137 138	spin_lock_irqsave(&front_info->io_lock, flags);139	req = be_prepare_req(evtchnl, XENDISPL_OP_SET_CONFIG);140	req->op.set_config.x = x;141	req->op.set_config.y = y;142	req->op.set_config.width = width;143	req->op.set_config.height = height;144	req->op.set_config.bpp = bpp;145	req->op.set_config.fb_cookie = fb_cookie;146 147	ret = be_stream_do_io(evtchnl, req);148	spin_unlock_irqrestore(&front_info->io_lock, flags);149 150	if (ret == 0)151		ret = be_stream_wait_io(evtchnl);152 153	mutex_unlock(&evtchnl->u.req.req_io_lock);154	return ret;155}156 157int xen_drm_front_dbuf_create(struct xen_drm_front_info *front_info,158			      u64 dbuf_cookie, u32 width, u32 height,159			      u32 bpp, u64 size, u32 offset,160			      struct page **pages)161{162	struct xen_drm_front_evtchnl *evtchnl;163	struct xen_drm_front_dbuf *dbuf;164	struct xendispl_req *req;165	struct xen_front_pgdir_shbuf_cfg buf_cfg;166	unsigned long flags;167	int ret;168 169	evtchnl = &front_info->evt_pairs[GENERIC_OP_EVT_CHNL].req;170	if (unlikely(!evtchnl))171		return -EIO;172 173	dbuf = kzalloc(sizeof(*dbuf), GFP_KERNEL);174	if (!dbuf)175		return -ENOMEM;176 177	dbuf_add_to_list(front_info, dbuf, dbuf_cookie);178 179	memset(&buf_cfg, 0, sizeof(buf_cfg));180	buf_cfg.xb_dev = front_info->xb_dev;181	buf_cfg.num_pages = DIV_ROUND_UP(size, PAGE_SIZE);182	buf_cfg.pages = pages;183	buf_cfg.pgdir = &dbuf->shbuf;184	buf_cfg.be_alloc = front_info->cfg.be_alloc;185 186	ret = xen_front_pgdir_shbuf_alloc(&buf_cfg);187	if (ret < 0)188		goto fail_shbuf_alloc;189 190	mutex_lock(&evtchnl->u.req.req_io_lock);191 192	spin_lock_irqsave(&front_info->io_lock, flags);193	req = be_prepare_req(evtchnl, XENDISPL_OP_DBUF_CREATE);194	req->op.dbuf_create.gref_directory =195			xen_front_pgdir_shbuf_get_dir_start(&dbuf->shbuf);196	req->op.dbuf_create.buffer_sz = size;197	req->op.dbuf_create.data_ofs = offset;198	req->op.dbuf_create.dbuf_cookie = dbuf_cookie;199	req->op.dbuf_create.width = width;200	req->op.dbuf_create.height = height;201	req->op.dbuf_create.bpp = bpp;202	if (buf_cfg.be_alloc)203		req->op.dbuf_create.flags |= XENDISPL_DBUF_FLG_REQ_ALLOC;204 205	ret = be_stream_do_io(evtchnl, req);206	spin_unlock_irqrestore(&front_info->io_lock, flags);207 208	if (ret < 0)209		goto fail;210 211	ret = be_stream_wait_io(evtchnl);212	if (ret < 0)213		goto fail;214 215	ret = xen_front_pgdir_shbuf_map(&dbuf->shbuf);216	if (ret < 0)217		goto fail;218 219	mutex_unlock(&evtchnl->u.req.req_io_lock);220	return 0;221 222fail:223	mutex_unlock(&evtchnl->u.req.req_io_lock);224fail_shbuf_alloc:225	dbuf_free(&front_info->dbuf_list, dbuf_cookie);226	return ret;227}228 229static int xen_drm_front_dbuf_destroy(struct xen_drm_front_info *front_info,230				      u64 dbuf_cookie)231{232	struct xen_drm_front_evtchnl *evtchnl;233	struct xendispl_req *req;234	unsigned long flags;235	bool be_alloc;236	int ret;237 238	evtchnl = &front_info->evt_pairs[GENERIC_OP_EVT_CHNL].req;239	if (unlikely(!evtchnl))240		return -EIO;241 242	be_alloc = front_info->cfg.be_alloc;243 244	/*245	 * For the backend allocated buffer release references now, so backend246	 * can free the buffer.247	 */248	if (be_alloc)249		dbuf_free(&front_info->dbuf_list, dbuf_cookie);250 251	mutex_lock(&evtchnl->u.req.req_io_lock);252 253	spin_lock_irqsave(&front_info->io_lock, flags);254	req = be_prepare_req(evtchnl, XENDISPL_OP_DBUF_DESTROY);255	req->op.dbuf_destroy.dbuf_cookie = dbuf_cookie;256 257	ret = be_stream_do_io(evtchnl, req);258	spin_unlock_irqrestore(&front_info->io_lock, flags);259 260	if (ret == 0)261		ret = be_stream_wait_io(evtchnl);262 263	/*264	 * Do this regardless of communication status with the backend:265	 * if we cannot remove remote resources remove what we can locally.266	 */267	if (!be_alloc)268		dbuf_free(&front_info->dbuf_list, dbuf_cookie);269 270	mutex_unlock(&evtchnl->u.req.req_io_lock);271	return ret;272}273 274int xen_drm_front_fb_attach(struct xen_drm_front_info *front_info,275			    u64 dbuf_cookie, u64 fb_cookie, u32 width,276			    u32 height, u32 pixel_format)277{278	struct xen_drm_front_evtchnl *evtchnl;279	struct xen_drm_front_dbuf *buf;280	struct xendispl_req *req;281	unsigned long flags;282	int ret;283 284	evtchnl = &front_info->evt_pairs[GENERIC_OP_EVT_CHNL].req;285	if (unlikely(!evtchnl))286		return -EIO;287 288	buf = dbuf_get(&front_info->dbuf_list, dbuf_cookie);289	if (!buf)290		return -EINVAL;291 292	buf->fb_cookie = fb_cookie;293 294	mutex_lock(&evtchnl->u.req.req_io_lock);295 296	spin_lock_irqsave(&front_info->io_lock, flags);297	req = be_prepare_req(evtchnl, XENDISPL_OP_FB_ATTACH);298	req->op.fb_attach.dbuf_cookie = dbuf_cookie;299	req->op.fb_attach.fb_cookie = fb_cookie;300	req->op.fb_attach.width = width;301	req->op.fb_attach.height = height;302	req->op.fb_attach.pixel_format = pixel_format;303 304	ret = be_stream_do_io(evtchnl, req);305	spin_unlock_irqrestore(&front_info->io_lock, flags);306 307	if (ret == 0)308		ret = be_stream_wait_io(evtchnl);309 310	mutex_unlock(&evtchnl->u.req.req_io_lock);311	return ret;312}313 314int xen_drm_front_fb_detach(struct xen_drm_front_info *front_info,315			    u64 fb_cookie)316{317	struct xen_drm_front_evtchnl *evtchnl;318	struct xendispl_req *req;319	unsigned long flags;320	int ret;321 322	evtchnl = &front_info->evt_pairs[GENERIC_OP_EVT_CHNL].req;323	if (unlikely(!evtchnl))324		return -EIO;325 326	mutex_lock(&evtchnl->u.req.req_io_lock);327 328	spin_lock_irqsave(&front_info->io_lock, flags);329	req = be_prepare_req(evtchnl, XENDISPL_OP_FB_DETACH);330	req->op.fb_detach.fb_cookie = fb_cookie;331 332	ret = be_stream_do_io(evtchnl, req);333	spin_unlock_irqrestore(&front_info->io_lock, flags);334 335	if (ret == 0)336		ret = be_stream_wait_io(evtchnl);337 338	mutex_unlock(&evtchnl->u.req.req_io_lock);339	return ret;340}341 342int xen_drm_front_page_flip(struct xen_drm_front_info *front_info,343			    int conn_idx, u64 fb_cookie)344{345	struct xen_drm_front_evtchnl *evtchnl;346	struct xendispl_req *req;347	unsigned long flags;348	int ret;349 350	if (unlikely(conn_idx >= front_info->num_evt_pairs))351		return -EINVAL;352 353	evtchnl = &front_info->evt_pairs[conn_idx].req;354 355	mutex_lock(&evtchnl->u.req.req_io_lock);356 357	spin_lock_irqsave(&front_info->io_lock, flags);358	req = be_prepare_req(evtchnl, XENDISPL_OP_PG_FLIP);359	req->op.pg_flip.fb_cookie = fb_cookie;360 361	ret = be_stream_do_io(evtchnl, req);362	spin_unlock_irqrestore(&front_info->io_lock, flags);363 364	if (ret == 0)365		ret = be_stream_wait_io(evtchnl);366 367	mutex_unlock(&evtchnl->u.req.req_io_lock);368	return ret;369}370 371void xen_drm_front_on_frame_done(struct xen_drm_front_info *front_info,372				 int conn_idx, u64 fb_cookie)373{374	struct xen_drm_front_drm_info *drm_info = front_info->drm_info;375 376	if (unlikely(conn_idx >= front_info->cfg.num_connectors))377		return;378 379	xen_drm_front_kms_on_frame_done(&drm_info->pipeline[conn_idx],380					fb_cookie);381}382 383void xen_drm_front_gem_object_free(struct drm_gem_object *obj)384{385	struct xen_drm_front_drm_info *drm_info = obj->dev->dev_private;386	int idx;387 388	if (drm_dev_enter(obj->dev, &idx)) {389		xen_drm_front_dbuf_destroy(drm_info->front_info,390					   xen_drm_front_dbuf_to_cookie(obj));391		drm_dev_exit(idx);392	} else {393		dbuf_free(&drm_info->front_info->dbuf_list,394			  xen_drm_front_dbuf_to_cookie(obj));395	}396 397	xen_drm_front_gem_free_object_unlocked(obj);398}399 400static int xen_drm_drv_dumb_create(struct drm_file *filp,401				   struct drm_device *dev,402				   struct drm_mode_create_dumb *args)403{404	struct xen_drm_front_drm_info *drm_info = dev->dev_private;405	struct drm_gem_object *obj;406	int ret;407 408	/*409	 * Dumb creation is a two stage process: first we create a fully410	 * constructed GEM object which is communicated to the backend, and411	 * only after that we can create GEM's handle. This is done so,412	 * because of the possible races: once you create a handle it becomes413	 * immediately visible to user-space, so the latter can try accessing414	 * object without pages etc.415	 * For details also see drm_gem_handle_create416	 */417	args->pitch = DIV_ROUND_UP(args->width * args->bpp, 8);418	args->size = args->pitch * args->height;419 420	obj = xen_drm_front_gem_create(dev, args->size);421	if (IS_ERR(obj)) {422		ret = PTR_ERR(obj);423		goto fail;424	}425 426	ret = xen_drm_front_dbuf_create(drm_info->front_info,427					xen_drm_front_dbuf_to_cookie(obj),428					args->width, args->height, args->bpp,429					args->size, 0,430					xen_drm_front_gem_get_pages(obj));431	if (ret)432		goto fail_backend;433 434	/* This is the tail of GEM object creation */435	ret = drm_gem_handle_create(filp, obj, &args->handle);436	if (ret)437		goto fail_handle;438 439	/* Drop reference from allocate - handle holds it now */440	drm_gem_object_put(obj);441	return 0;442 443fail_handle:444	xen_drm_front_dbuf_destroy(drm_info->front_info,445				   xen_drm_front_dbuf_to_cookie(obj));446fail_backend:447	/* drop reference from allocate */448	drm_gem_object_put(obj);449fail:450	DRM_ERROR("Failed to create dumb buffer: %d\n", ret);451	return ret;452}453 454static void xen_drm_drv_release(struct drm_device *dev)455{456	struct xen_drm_front_drm_info *drm_info = dev->dev_private;457	struct xen_drm_front_info *front_info = drm_info->front_info;458 459	xen_drm_front_kms_fini(drm_info);460 461	drm_atomic_helper_shutdown(dev);462	drm_mode_config_cleanup(dev);463 464	if (front_info->cfg.be_alloc)465		xenbus_switch_state(front_info->xb_dev,466				    XenbusStateInitialising);467 468	kfree(drm_info);469}470 471DEFINE_DRM_GEM_FOPS(xen_drm_dev_fops);472 473static const struct drm_driver xen_drm_driver = {474	.driver_features           = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,475	.release                   = xen_drm_drv_release,476	.gem_prime_import_sg_table = xen_drm_front_gem_import_sg_table,477	.dumb_create               = xen_drm_drv_dumb_create,478	.fops                      = &xen_drm_dev_fops,479	.name                      = "xendrm-du",480	.desc                      = "Xen PV DRM Display Unit",481	.date                      = "20180221",482	.major                     = 1,483	.minor                     = 0,484 485};486 487static int xen_drm_drv_init(struct xen_drm_front_info *front_info)488{489	struct device *dev = &front_info->xb_dev->dev;490	struct xen_drm_front_drm_info *drm_info;491	struct drm_device *drm_dev;492	int ret;493 494	if (drm_firmware_drivers_only())495		return -ENODEV;496 497	DRM_INFO("Creating %s\n", xen_drm_driver.desc);498 499	drm_info = kzalloc(sizeof(*drm_info), GFP_KERNEL);500	if (!drm_info) {501		ret = -ENOMEM;502		goto fail;503	}504 505	drm_info->front_info = front_info;506	front_info->drm_info = drm_info;507 508	drm_dev = drm_dev_alloc(&xen_drm_driver, dev);509	if (IS_ERR(drm_dev)) {510		ret = PTR_ERR(drm_dev);511		goto fail_dev;512	}513 514	drm_info->drm_dev = drm_dev;515 516	drm_dev->dev_private = drm_info;517 518	ret = xen_drm_front_kms_init(drm_info);519	if (ret) {520		DRM_ERROR("Failed to initialize DRM/KMS, ret %d\n", ret);521		goto fail_modeset;522	}523 524	ret = drm_dev_register(drm_dev, 0);525	if (ret)526		goto fail_register;527 528	DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",529		 xen_drm_driver.name, xen_drm_driver.major,530		 xen_drm_driver.minor, xen_drm_driver.patchlevel,531		 xen_drm_driver.date, drm_dev->primary->index);532 533	return 0;534 535fail_register:536	drm_dev_unregister(drm_dev);537fail_modeset:538	drm_kms_helper_poll_fini(drm_dev);539	drm_mode_config_cleanup(drm_dev);540	drm_dev_put(drm_dev);541fail_dev:542	kfree(drm_info);543	front_info->drm_info = NULL;544fail:545	return ret;546}547 548static void xen_drm_drv_fini(struct xen_drm_front_info *front_info)549{550	struct xen_drm_front_drm_info *drm_info = front_info->drm_info;551	struct drm_device *dev;552 553	if (!drm_info)554		return;555 556	dev = drm_info->drm_dev;557	if (!dev)558		return;559 560	/* Nothing to do if device is already unplugged */561	if (drm_dev_is_unplugged(dev))562		return;563 564	drm_kms_helper_poll_fini(dev);565	drm_dev_unplug(dev);566	drm_dev_put(dev);567 568	front_info->drm_info = NULL;569 570	xen_drm_front_evtchnl_free_all(front_info);571	dbuf_free_all(&front_info->dbuf_list);572 573	/*574	 * If we are not using backend allocated buffers, then tell the575	 * backend we are ready to (re)initialize. Otherwise, wait for576	 * drm_driver.release.577	 */578	if (!front_info->cfg.be_alloc)579		xenbus_switch_state(front_info->xb_dev,580				    XenbusStateInitialising);581}582 583static int displback_initwait(struct xen_drm_front_info *front_info)584{585	struct xen_drm_front_cfg *cfg = &front_info->cfg;586	int ret;587 588	cfg->front_info = front_info;589	ret = xen_drm_front_cfg_card(front_info, cfg);590	if (ret < 0)591		return ret;592 593	DRM_INFO("Have %d connector(s)\n", cfg->num_connectors);594	/* Create event channels for all connectors and publish */595	ret = xen_drm_front_evtchnl_create_all(front_info);596	if (ret < 0)597		return ret;598 599	return xen_drm_front_evtchnl_publish_all(front_info);600}601 602static int displback_connect(struct xen_drm_front_info *front_info)603{604	xen_drm_front_evtchnl_set_state(front_info, EVTCHNL_STATE_CONNECTED);605	return xen_drm_drv_init(front_info);606}607 608static void displback_disconnect(struct xen_drm_front_info *front_info)609{610	if (!front_info->drm_info)611		return;612 613	/* Tell the backend to wait until we release the DRM driver. */614	xenbus_switch_state(front_info->xb_dev, XenbusStateReconfiguring);615 616	xen_drm_drv_fini(front_info);617}618 619static void displback_changed(struct xenbus_device *xb_dev,620			      enum xenbus_state backend_state)621{622	struct xen_drm_front_info *front_info = dev_get_drvdata(&xb_dev->dev);623	int ret;624 625	DRM_DEBUG("Backend state is %s, front is %s\n",626		  xenbus_strstate(backend_state),627		  xenbus_strstate(xb_dev->state));628 629	switch (backend_state) {630	case XenbusStateReconfiguring:631	case XenbusStateReconfigured:632	case XenbusStateInitialised:633		break;634 635	case XenbusStateInitialising:636		if (xb_dev->state == XenbusStateReconfiguring)637			break;638 639		/* recovering after backend unexpected closure */640		displback_disconnect(front_info);641		break;642 643	case XenbusStateInitWait:644		if (xb_dev->state == XenbusStateReconfiguring)645			break;646 647		/* recovering after backend unexpected closure */648		displback_disconnect(front_info);649		if (xb_dev->state != XenbusStateInitialising)650			break;651 652		ret = displback_initwait(front_info);653		if (ret < 0)654			xenbus_dev_fatal(xb_dev, ret, "initializing frontend");655		else656			xenbus_switch_state(xb_dev, XenbusStateInitialised);657		break;658 659	case XenbusStateConnected:660		if (xb_dev->state != XenbusStateInitialised)661			break;662 663		ret = displback_connect(front_info);664		if (ret < 0) {665			displback_disconnect(front_info);666			xenbus_dev_fatal(xb_dev, ret, "connecting backend");667		} else {668			xenbus_switch_state(xb_dev, XenbusStateConnected);669		}670		break;671 672	case XenbusStateClosing:673		/*674		 * in this state backend starts freeing resources,675		 * so let it go into closed state, so we can also676		 * remove ours677		 */678		break;679 680	case XenbusStateUnknown:681	case XenbusStateClosed:682		if (xb_dev->state == XenbusStateClosed)683			break;684 685		displback_disconnect(front_info);686		break;687	}688}689 690static int xen_drv_probe(struct xenbus_device *xb_dev,691			 const struct xenbus_device_id *id)692{693	struct xen_drm_front_info *front_info;694	struct device *dev = &xb_dev->dev;695	int ret;696 697	ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(64));698	if (ret < 0) {699		DRM_ERROR("Cannot setup DMA mask, ret %d", ret);700		return ret;701	}702 703	front_info = devm_kzalloc(&xb_dev->dev,704				  sizeof(*front_info), GFP_KERNEL);705	if (!front_info)706		return -ENOMEM;707 708	front_info->xb_dev = xb_dev;709	spin_lock_init(&front_info->io_lock);710	INIT_LIST_HEAD(&front_info->dbuf_list);711	dev_set_drvdata(&xb_dev->dev, front_info);712 713	return xenbus_switch_state(xb_dev, XenbusStateInitialising);714}715 716static void xen_drv_remove(struct xenbus_device *dev)717{718	struct xen_drm_front_info *front_info = dev_get_drvdata(&dev->dev);719	int to = 100;720 721	xenbus_switch_state(dev, XenbusStateClosing);722 723	/*724	 * On driver removal it is disconnected from XenBus,725	 * so no backend state change events come via .otherend_changed726	 * callback. This prevents us from exiting gracefully, e.g.727	 * signaling the backend to free event channels, waiting for its728	 * state to change to XenbusStateClosed and cleaning at our end.729	 * Normally when front driver removed backend will finally go into730	 * XenbusStateInitWait state.731	 *732	 * Workaround: read backend's state manually and wait with time-out.733	 */734	while ((xenbus_read_unsigned(front_info->xb_dev->otherend, "state",735				     XenbusStateUnknown) != XenbusStateInitWait) &&736				     --to)737		msleep(10);738 739	if (!to) {740		unsigned int state;741 742		state = xenbus_read_unsigned(front_info->xb_dev->otherend,743					     "state", XenbusStateUnknown);744		DRM_ERROR("Backend state is %s while removing driver\n",745			  xenbus_strstate(state));746	}747 748	xen_drm_drv_fini(front_info);749	xenbus_frontend_closed(dev);750}751 752static const struct xenbus_device_id xen_driver_ids[] = {753	{ XENDISPL_DRIVER_NAME },754	{ "" }755};756 757static struct xenbus_driver xen_driver = {758	.ids = xen_driver_ids,759	.probe = xen_drv_probe,760	.remove = xen_drv_remove,761	.otherend_changed = displback_changed,762	.not_essential = true,763};764 765static int __init xen_drv_init(void)766{767	/* At the moment we only support case with XEN_PAGE_SIZE == PAGE_SIZE */768	if (XEN_PAGE_SIZE != PAGE_SIZE) {769		DRM_ERROR(XENDISPL_DRIVER_NAME ": different kernel and Xen page sizes are not supported: XEN_PAGE_SIZE (%lu) != PAGE_SIZE (%lu)\n",770			  XEN_PAGE_SIZE, PAGE_SIZE);771		return -ENODEV;772	}773 774	if (!xen_domain())775		return -ENODEV;776 777	if (!xen_has_pv_devices())778		return -ENODEV;779 780	DRM_INFO("Registering XEN PV " XENDISPL_DRIVER_NAME "\n");781	return xenbus_register_frontend(&xen_driver);782}783 784static void __exit xen_drv_fini(void)785{786	DRM_INFO("Unregistering XEN PV " XENDISPL_DRIVER_NAME "\n");787	xenbus_unregister_driver(&xen_driver);788}789 790module_init(xen_drv_init);791module_exit(xen_drv_fini);792 793MODULE_DESCRIPTION("Xen para-virtualized display device frontend");794MODULE_LICENSE("GPL");795MODULE_ALIAS("xen:" XENDISPL_DRIVER_NAME);796