xref: /linux/drivers/gpu/drm/xen/xen_drm_front_evtchnl.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1c575b7eeSOleksandr Andrushchenko // SPDX-License-Identifier: GPL-2.0 OR MIT
2c575b7eeSOleksandr Andrushchenko 
3c575b7eeSOleksandr Andrushchenko /*
4c575b7eeSOleksandr Andrushchenko  *  Xen para-virtual DRM device
5c575b7eeSOleksandr Andrushchenko  *
6c575b7eeSOleksandr Andrushchenko  * Copyright (C) 2016-2018 EPAM Systems Inc.
7c575b7eeSOleksandr Andrushchenko  *
8c575b7eeSOleksandr Andrushchenko  * Author: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
9c575b7eeSOleksandr Andrushchenko  */
10c575b7eeSOleksandr Andrushchenko 
11c575b7eeSOleksandr Andrushchenko #include <linux/errno.h>
12c575b7eeSOleksandr Andrushchenko #include <linux/irq.h>
13c575b7eeSOleksandr Andrushchenko 
142ea2269eSSam Ravnborg #include <drm/drm_print.h>
152ea2269eSSam Ravnborg 
16c575b7eeSOleksandr Andrushchenko #include <xen/xenbus.h>
17c575b7eeSOleksandr Andrushchenko #include <xen/events.h>
18c575b7eeSOleksandr Andrushchenko #include <xen/grant_table.h>
19c575b7eeSOleksandr Andrushchenko 
20c575b7eeSOleksandr Andrushchenko #include "xen_drm_front.h"
21c575b7eeSOleksandr Andrushchenko #include "xen_drm_front_evtchnl.h"
22c575b7eeSOleksandr Andrushchenko 
evtchnl_interrupt_ctrl(int irq,void * dev_id)23c575b7eeSOleksandr Andrushchenko static irqreturn_t evtchnl_interrupt_ctrl(int irq, void *dev_id)
24c575b7eeSOleksandr Andrushchenko {
25c575b7eeSOleksandr Andrushchenko 	struct xen_drm_front_evtchnl *evtchnl = dev_id;
26c575b7eeSOleksandr Andrushchenko 	struct xen_drm_front_info *front_info = evtchnl->front_info;
27c575b7eeSOleksandr Andrushchenko 	struct xendispl_resp *resp;
28c575b7eeSOleksandr Andrushchenko 	RING_IDX i, rp;
29c575b7eeSOleksandr Andrushchenko 	unsigned long flags;
30c575b7eeSOleksandr Andrushchenko 
31c575b7eeSOleksandr Andrushchenko 	if (unlikely(evtchnl->state != EVTCHNL_STATE_CONNECTED))
32c575b7eeSOleksandr Andrushchenko 		return IRQ_HANDLED;
33c575b7eeSOleksandr Andrushchenko 
34c575b7eeSOleksandr Andrushchenko 	spin_lock_irqsave(&front_info->io_lock, flags);
35c575b7eeSOleksandr Andrushchenko 
36c575b7eeSOleksandr Andrushchenko again:
37c575b7eeSOleksandr Andrushchenko 	rp = evtchnl->u.req.ring.sring->rsp_prod;
38c575b7eeSOleksandr Andrushchenko 	/* ensure we see queued responses up to rp */
39c575b7eeSOleksandr Andrushchenko 	virt_rmb();
40c575b7eeSOleksandr Andrushchenko 
41c575b7eeSOleksandr Andrushchenko 	for (i = evtchnl->u.req.ring.rsp_cons; i != rp; i++) {
42c575b7eeSOleksandr Andrushchenko 		resp = RING_GET_RESPONSE(&evtchnl->u.req.ring, i);
43c575b7eeSOleksandr Andrushchenko 		if (unlikely(resp->id != evtchnl->evt_id))
44c575b7eeSOleksandr Andrushchenko 			continue;
45c575b7eeSOleksandr Andrushchenko 
46c575b7eeSOleksandr Andrushchenko 		switch (resp->operation) {
47c575b7eeSOleksandr Andrushchenko 		case XENDISPL_OP_PG_FLIP:
48c575b7eeSOleksandr Andrushchenko 		case XENDISPL_OP_FB_ATTACH:
49c575b7eeSOleksandr Andrushchenko 		case XENDISPL_OP_FB_DETACH:
50c575b7eeSOleksandr Andrushchenko 		case XENDISPL_OP_DBUF_CREATE:
51c575b7eeSOleksandr Andrushchenko 		case XENDISPL_OP_DBUF_DESTROY:
52c575b7eeSOleksandr Andrushchenko 		case XENDISPL_OP_SET_CONFIG:
53c575b7eeSOleksandr Andrushchenko 			evtchnl->u.req.resp_status = resp->status;
54c575b7eeSOleksandr Andrushchenko 			complete(&evtchnl->u.req.completion);
55c575b7eeSOleksandr Andrushchenko 			break;
56c575b7eeSOleksandr Andrushchenko 
57c575b7eeSOleksandr Andrushchenko 		default:
58c575b7eeSOleksandr Andrushchenko 			DRM_ERROR("Operation %d is not supported\n",
59c575b7eeSOleksandr Andrushchenko 				  resp->operation);
60c575b7eeSOleksandr Andrushchenko 			break;
61c575b7eeSOleksandr Andrushchenko 		}
62c575b7eeSOleksandr Andrushchenko 	}
63c575b7eeSOleksandr Andrushchenko 
64c575b7eeSOleksandr Andrushchenko 	evtchnl->u.req.ring.rsp_cons = i;
65c575b7eeSOleksandr Andrushchenko 
66c575b7eeSOleksandr Andrushchenko 	if (i != evtchnl->u.req.ring.req_prod_pvt) {
67c575b7eeSOleksandr Andrushchenko 		int more_to_do;
68c575b7eeSOleksandr Andrushchenko 
69c575b7eeSOleksandr Andrushchenko 		RING_FINAL_CHECK_FOR_RESPONSES(&evtchnl->u.req.ring,
70c575b7eeSOleksandr Andrushchenko 					       more_to_do);
71c575b7eeSOleksandr Andrushchenko 		if (more_to_do)
72c575b7eeSOleksandr Andrushchenko 			goto again;
73c575b7eeSOleksandr Andrushchenko 	} else {
74c575b7eeSOleksandr Andrushchenko 		evtchnl->u.req.ring.sring->rsp_event = i + 1;
75c575b7eeSOleksandr Andrushchenko 	}
76c575b7eeSOleksandr Andrushchenko 
77c575b7eeSOleksandr Andrushchenko 	spin_unlock_irqrestore(&front_info->io_lock, flags);
78c575b7eeSOleksandr Andrushchenko 	return IRQ_HANDLED;
79c575b7eeSOleksandr Andrushchenko }
80c575b7eeSOleksandr Andrushchenko 
evtchnl_interrupt_evt(int irq,void * dev_id)81c575b7eeSOleksandr Andrushchenko static irqreturn_t evtchnl_interrupt_evt(int irq, void *dev_id)
82c575b7eeSOleksandr Andrushchenko {
83c575b7eeSOleksandr Andrushchenko 	struct xen_drm_front_evtchnl *evtchnl = dev_id;
84c575b7eeSOleksandr Andrushchenko 	struct xen_drm_front_info *front_info = evtchnl->front_info;
85c575b7eeSOleksandr Andrushchenko 	struct xendispl_event_page *page = evtchnl->u.evt.page;
86c575b7eeSOleksandr Andrushchenko 	u32 cons, prod;
87c575b7eeSOleksandr Andrushchenko 	unsigned long flags;
88c575b7eeSOleksandr Andrushchenko 
89c575b7eeSOleksandr Andrushchenko 	if (unlikely(evtchnl->state != EVTCHNL_STATE_CONNECTED))
90c575b7eeSOleksandr Andrushchenko 		return IRQ_HANDLED;
91c575b7eeSOleksandr Andrushchenko 
92c575b7eeSOleksandr Andrushchenko 	spin_lock_irqsave(&front_info->io_lock, flags);
93c575b7eeSOleksandr Andrushchenko 
94c575b7eeSOleksandr Andrushchenko 	prod = page->in_prod;
95c575b7eeSOleksandr Andrushchenko 	/* ensure we see ring contents up to prod */
96c575b7eeSOleksandr Andrushchenko 	virt_rmb();
97c575b7eeSOleksandr Andrushchenko 	if (prod == page->in_cons)
98c575b7eeSOleksandr Andrushchenko 		goto out;
99c575b7eeSOleksandr Andrushchenko 
100c575b7eeSOleksandr Andrushchenko 	for (cons = page->in_cons; cons != prod; cons++) {
101c575b7eeSOleksandr Andrushchenko 		struct xendispl_evt *event;
102c575b7eeSOleksandr Andrushchenko 
103c575b7eeSOleksandr Andrushchenko 		event = &XENDISPL_IN_RING_REF(page, cons);
104c575b7eeSOleksandr Andrushchenko 		if (unlikely(event->id != evtchnl->evt_id++))
105c575b7eeSOleksandr Andrushchenko 			continue;
106c575b7eeSOleksandr Andrushchenko 
107c575b7eeSOleksandr Andrushchenko 		switch (event->type) {
108c575b7eeSOleksandr Andrushchenko 		case XENDISPL_EVT_PG_FLIP:
109c575b7eeSOleksandr Andrushchenko 			xen_drm_front_on_frame_done(front_info, evtchnl->index,
110c575b7eeSOleksandr Andrushchenko 						    event->op.pg_flip.fb_cookie);
111c575b7eeSOleksandr Andrushchenko 			break;
112c575b7eeSOleksandr Andrushchenko 		}
113c575b7eeSOleksandr Andrushchenko 	}
114c575b7eeSOleksandr Andrushchenko 	page->in_cons = cons;
115c575b7eeSOleksandr Andrushchenko 	/* ensure ring contents */
116c575b7eeSOleksandr Andrushchenko 	virt_wmb();
117c575b7eeSOleksandr Andrushchenko 
118c575b7eeSOleksandr Andrushchenko out:
119c575b7eeSOleksandr Andrushchenko 	spin_unlock_irqrestore(&front_info->io_lock, flags);
120c575b7eeSOleksandr Andrushchenko 	return IRQ_HANDLED;
121c575b7eeSOleksandr Andrushchenko }
122c575b7eeSOleksandr Andrushchenko 
evtchnl_free(struct xen_drm_front_info * front_info,struct xen_drm_front_evtchnl * evtchnl)123c575b7eeSOleksandr Andrushchenko static void evtchnl_free(struct xen_drm_front_info *front_info,
124c575b7eeSOleksandr Andrushchenko 			 struct xen_drm_front_evtchnl *evtchnl)
125c575b7eeSOleksandr Andrushchenko {
126*ae19265cSJuergen Gross 	void *page = NULL;
127c575b7eeSOleksandr Andrushchenko 
128c575b7eeSOleksandr Andrushchenko 	if (evtchnl->type == EVTCHNL_TYPE_REQ)
129*ae19265cSJuergen Gross 		page = evtchnl->u.req.ring.sring;
130c575b7eeSOleksandr Andrushchenko 	else if (evtchnl->type == EVTCHNL_TYPE_EVT)
131*ae19265cSJuergen Gross 		page = evtchnl->u.evt.page;
132c575b7eeSOleksandr Andrushchenko 	if (!page)
133c575b7eeSOleksandr Andrushchenko 		return;
134c575b7eeSOleksandr Andrushchenko 
135c575b7eeSOleksandr Andrushchenko 	evtchnl->state = EVTCHNL_STATE_DISCONNECTED;
136c575b7eeSOleksandr Andrushchenko 
137c575b7eeSOleksandr Andrushchenko 	if (evtchnl->type == EVTCHNL_TYPE_REQ) {
138c575b7eeSOleksandr Andrushchenko 		/* release all who still waits for response if any */
139c575b7eeSOleksandr Andrushchenko 		evtchnl->u.req.resp_status = -EIO;
140c575b7eeSOleksandr Andrushchenko 		complete_all(&evtchnl->u.req.completion);
141c575b7eeSOleksandr Andrushchenko 	}
142c575b7eeSOleksandr Andrushchenko 
143c575b7eeSOleksandr Andrushchenko 	if (evtchnl->irq)
144c575b7eeSOleksandr Andrushchenko 		unbind_from_irqhandler(evtchnl->irq, evtchnl);
145c575b7eeSOleksandr Andrushchenko 
146c575b7eeSOleksandr Andrushchenko 	if (evtchnl->port)
147c575b7eeSOleksandr Andrushchenko 		xenbus_free_evtchn(front_info->xb_dev, evtchnl->port);
148c575b7eeSOleksandr Andrushchenko 
149c575b7eeSOleksandr Andrushchenko 	/* end access and free the page */
150*ae19265cSJuergen Gross 	xenbus_teardown_ring(&page, 1, &evtchnl->gref);
151c575b7eeSOleksandr Andrushchenko 
152c575b7eeSOleksandr Andrushchenko 	memset(evtchnl, 0, sizeof(*evtchnl));
153c575b7eeSOleksandr Andrushchenko }
154c575b7eeSOleksandr Andrushchenko 
evtchnl_alloc(struct xen_drm_front_info * front_info,int index,struct xen_drm_front_evtchnl * evtchnl,enum xen_drm_front_evtchnl_type type)155c575b7eeSOleksandr Andrushchenko static int evtchnl_alloc(struct xen_drm_front_info *front_info, int index,
156c575b7eeSOleksandr Andrushchenko 			 struct xen_drm_front_evtchnl *evtchnl,
157c575b7eeSOleksandr Andrushchenko 			 enum xen_drm_front_evtchnl_type type)
158c575b7eeSOleksandr Andrushchenko {
159c575b7eeSOleksandr Andrushchenko 	struct xenbus_device *xb_dev = front_info->xb_dev;
160*ae19265cSJuergen Gross 	void *page;
161c575b7eeSOleksandr Andrushchenko 	irq_handler_t handler;
162c575b7eeSOleksandr Andrushchenko 	int ret;
163c575b7eeSOleksandr Andrushchenko 
164c575b7eeSOleksandr Andrushchenko 	memset(evtchnl, 0, sizeof(*evtchnl));
165c575b7eeSOleksandr Andrushchenko 	evtchnl->type = type;
166c575b7eeSOleksandr Andrushchenko 	evtchnl->index = index;
167c575b7eeSOleksandr Andrushchenko 	evtchnl->front_info = front_info;
168c575b7eeSOleksandr Andrushchenko 	evtchnl->state = EVTCHNL_STATE_DISCONNECTED;
169c575b7eeSOleksandr Andrushchenko 
170*ae19265cSJuergen Gross 	ret = xenbus_setup_ring(xb_dev, GFP_NOIO | __GFP_HIGH, &page,
171*ae19265cSJuergen Gross 				1, &evtchnl->gref);
172*ae19265cSJuergen Gross 	if (ret)
173c575b7eeSOleksandr Andrushchenko 		goto fail;
174c575b7eeSOleksandr Andrushchenko 
175c575b7eeSOleksandr Andrushchenko 	if (type == EVTCHNL_TYPE_REQ) {
176c575b7eeSOleksandr Andrushchenko 		struct xen_displif_sring *sring;
177c575b7eeSOleksandr Andrushchenko 
178c575b7eeSOleksandr Andrushchenko 		init_completion(&evtchnl->u.req.completion);
179c575b7eeSOleksandr Andrushchenko 		mutex_init(&evtchnl->u.req.req_io_lock);
180*ae19265cSJuergen Gross 		sring = page;
181*ae19265cSJuergen Gross 		XEN_FRONT_RING_INIT(&evtchnl->u.req.ring, sring, XEN_PAGE_SIZE);
182c575b7eeSOleksandr Andrushchenko 
183c575b7eeSOleksandr Andrushchenko 		handler = evtchnl_interrupt_ctrl;
184c575b7eeSOleksandr Andrushchenko 	} else {
185*ae19265cSJuergen Gross 		evtchnl->u.evt.page = page;
186c575b7eeSOleksandr Andrushchenko 		handler = evtchnl_interrupt_evt;
187c575b7eeSOleksandr Andrushchenko 	}
188c575b7eeSOleksandr Andrushchenko 
189c575b7eeSOleksandr Andrushchenko 	ret = xenbus_alloc_evtchn(xb_dev, &evtchnl->port);
190c575b7eeSOleksandr Andrushchenko 	if (ret < 0)
191c575b7eeSOleksandr Andrushchenko 		goto fail;
192c575b7eeSOleksandr Andrushchenko 
193c575b7eeSOleksandr Andrushchenko 	ret = bind_evtchn_to_irqhandler(evtchnl->port,
194c575b7eeSOleksandr Andrushchenko 					handler, 0, xb_dev->devicetype,
195c575b7eeSOleksandr Andrushchenko 					evtchnl);
196c575b7eeSOleksandr Andrushchenko 	if (ret < 0)
197c575b7eeSOleksandr Andrushchenko 		goto fail;
198c575b7eeSOleksandr Andrushchenko 
199c575b7eeSOleksandr Andrushchenko 	evtchnl->irq = ret;
200c575b7eeSOleksandr Andrushchenko 	return 0;
201c575b7eeSOleksandr Andrushchenko 
202c575b7eeSOleksandr Andrushchenko fail:
203c575b7eeSOleksandr Andrushchenko 	DRM_ERROR("Failed to allocate ring: %d\n", ret);
204c575b7eeSOleksandr Andrushchenko 	return ret;
205c575b7eeSOleksandr Andrushchenko }
206c575b7eeSOleksandr Andrushchenko 
xen_drm_front_evtchnl_create_all(struct xen_drm_front_info * front_info)207c575b7eeSOleksandr Andrushchenko int xen_drm_front_evtchnl_create_all(struct xen_drm_front_info *front_info)
208c575b7eeSOleksandr Andrushchenko {
209c575b7eeSOleksandr Andrushchenko 	struct xen_drm_front_cfg *cfg;
210c575b7eeSOleksandr Andrushchenko 	int ret, conn;
211c575b7eeSOleksandr Andrushchenko 
212c575b7eeSOleksandr Andrushchenko 	cfg = &front_info->cfg;
213c575b7eeSOleksandr Andrushchenko 
214c575b7eeSOleksandr Andrushchenko 	front_info->evt_pairs =
215c575b7eeSOleksandr Andrushchenko 			kcalloc(cfg->num_connectors,
216c575b7eeSOleksandr Andrushchenko 				sizeof(struct xen_drm_front_evtchnl_pair),
217c575b7eeSOleksandr Andrushchenko 				GFP_KERNEL);
218c575b7eeSOleksandr Andrushchenko 	if (!front_info->evt_pairs) {
219c575b7eeSOleksandr Andrushchenko 		ret = -ENOMEM;
220c575b7eeSOleksandr Andrushchenko 		goto fail;
221c575b7eeSOleksandr Andrushchenko 	}
222c575b7eeSOleksandr Andrushchenko 
223c575b7eeSOleksandr Andrushchenko 	for (conn = 0; conn < cfg->num_connectors; conn++) {
224c575b7eeSOleksandr Andrushchenko 		ret = evtchnl_alloc(front_info, conn,
225c575b7eeSOleksandr Andrushchenko 				    &front_info->evt_pairs[conn].req,
226c575b7eeSOleksandr Andrushchenko 				    EVTCHNL_TYPE_REQ);
227c575b7eeSOleksandr Andrushchenko 		if (ret < 0) {
228c575b7eeSOleksandr Andrushchenko 			DRM_ERROR("Error allocating control channel\n");
229c575b7eeSOleksandr Andrushchenko 			goto fail;
230c575b7eeSOleksandr Andrushchenko 		}
231c575b7eeSOleksandr Andrushchenko 
232c575b7eeSOleksandr Andrushchenko 		ret = evtchnl_alloc(front_info, conn,
233c575b7eeSOleksandr Andrushchenko 				    &front_info->evt_pairs[conn].evt,
234c575b7eeSOleksandr Andrushchenko 				    EVTCHNL_TYPE_EVT);
235c575b7eeSOleksandr Andrushchenko 		if (ret < 0) {
236c575b7eeSOleksandr Andrushchenko 			DRM_ERROR("Error allocating in-event channel\n");
237c575b7eeSOleksandr Andrushchenko 			goto fail;
238c575b7eeSOleksandr Andrushchenko 		}
239c575b7eeSOleksandr Andrushchenko 	}
240c575b7eeSOleksandr Andrushchenko 	front_info->num_evt_pairs = cfg->num_connectors;
241c575b7eeSOleksandr Andrushchenko 	return 0;
242c575b7eeSOleksandr Andrushchenko 
243c575b7eeSOleksandr Andrushchenko fail:
244c575b7eeSOleksandr Andrushchenko 	xen_drm_front_evtchnl_free_all(front_info);
245c575b7eeSOleksandr Andrushchenko 	return ret;
246c575b7eeSOleksandr Andrushchenko }
247c575b7eeSOleksandr Andrushchenko 
evtchnl_publish(struct xenbus_transaction xbt,struct xen_drm_front_evtchnl * evtchnl,const char * path,const char * node_ring,const char * node_chnl)248c575b7eeSOleksandr Andrushchenko static int evtchnl_publish(struct xenbus_transaction xbt,
249c575b7eeSOleksandr Andrushchenko 			   struct xen_drm_front_evtchnl *evtchnl,
250c575b7eeSOleksandr Andrushchenko 			   const char *path, const char *node_ring,
251c575b7eeSOleksandr Andrushchenko 			   const char *node_chnl)
252c575b7eeSOleksandr Andrushchenko {
253c575b7eeSOleksandr Andrushchenko 	struct xenbus_device *xb_dev = evtchnl->front_info->xb_dev;
254c575b7eeSOleksandr Andrushchenko 	int ret;
255c575b7eeSOleksandr Andrushchenko 
256c575b7eeSOleksandr Andrushchenko 	/* write control channel ring reference */
257c575b7eeSOleksandr Andrushchenko 	ret = xenbus_printf(xbt, path, node_ring, "%u", evtchnl->gref);
258c575b7eeSOleksandr Andrushchenko 	if (ret < 0) {
259c575b7eeSOleksandr Andrushchenko 		xenbus_dev_error(xb_dev, ret, "writing ring-ref");
260c575b7eeSOleksandr Andrushchenko 		return ret;
261c575b7eeSOleksandr Andrushchenko 	}
262c575b7eeSOleksandr Andrushchenko 
263c575b7eeSOleksandr Andrushchenko 	/* write event channel ring reference */
264c575b7eeSOleksandr Andrushchenko 	ret = xenbus_printf(xbt, path, node_chnl, "%u", evtchnl->port);
265c575b7eeSOleksandr Andrushchenko 	if (ret < 0) {
266c575b7eeSOleksandr Andrushchenko 		xenbus_dev_error(xb_dev, ret, "writing event channel");
267c575b7eeSOleksandr Andrushchenko 		return ret;
268c575b7eeSOleksandr Andrushchenko 	}
269c575b7eeSOleksandr Andrushchenko 
270c575b7eeSOleksandr Andrushchenko 	return 0;
271c575b7eeSOleksandr Andrushchenko }
272c575b7eeSOleksandr Andrushchenko 
xen_drm_front_evtchnl_publish_all(struct xen_drm_front_info * front_info)273c575b7eeSOleksandr Andrushchenko int xen_drm_front_evtchnl_publish_all(struct xen_drm_front_info *front_info)
274c575b7eeSOleksandr Andrushchenko {
275c575b7eeSOleksandr Andrushchenko 	struct xenbus_transaction xbt;
276c575b7eeSOleksandr Andrushchenko 	struct xen_drm_front_cfg *plat_data;
277c575b7eeSOleksandr Andrushchenko 	int ret, conn;
278c575b7eeSOleksandr Andrushchenko 
279c575b7eeSOleksandr Andrushchenko 	plat_data = &front_info->cfg;
280c575b7eeSOleksandr Andrushchenko 
281c575b7eeSOleksandr Andrushchenko again:
282c575b7eeSOleksandr Andrushchenko 	ret = xenbus_transaction_start(&xbt);
283c575b7eeSOleksandr Andrushchenko 	if (ret < 0) {
284c575b7eeSOleksandr Andrushchenko 		xenbus_dev_fatal(front_info->xb_dev, ret,
285c575b7eeSOleksandr Andrushchenko 				 "starting transaction");
286c575b7eeSOleksandr Andrushchenko 		return ret;
287c575b7eeSOleksandr Andrushchenko 	}
288c575b7eeSOleksandr Andrushchenko 
289c575b7eeSOleksandr Andrushchenko 	for (conn = 0; conn < plat_data->num_connectors; conn++) {
290c575b7eeSOleksandr Andrushchenko 		ret = evtchnl_publish(xbt, &front_info->evt_pairs[conn].req,
291c575b7eeSOleksandr Andrushchenko 				      plat_data->connectors[conn].xenstore_path,
292c575b7eeSOleksandr Andrushchenko 				      XENDISPL_FIELD_REQ_RING_REF,
293c575b7eeSOleksandr Andrushchenko 				      XENDISPL_FIELD_REQ_CHANNEL);
294c575b7eeSOleksandr Andrushchenko 		if (ret < 0)
295c575b7eeSOleksandr Andrushchenko 			goto fail;
296c575b7eeSOleksandr Andrushchenko 
297c575b7eeSOleksandr Andrushchenko 		ret = evtchnl_publish(xbt, &front_info->evt_pairs[conn].evt,
298c575b7eeSOleksandr Andrushchenko 				      plat_data->connectors[conn].xenstore_path,
299c575b7eeSOleksandr Andrushchenko 				      XENDISPL_FIELD_EVT_RING_REF,
300c575b7eeSOleksandr Andrushchenko 				      XENDISPL_FIELD_EVT_CHANNEL);
301c575b7eeSOleksandr Andrushchenko 		if (ret < 0)
302c575b7eeSOleksandr Andrushchenko 			goto fail;
303c575b7eeSOleksandr Andrushchenko 	}
304c575b7eeSOleksandr Andrushchenko 
305c575b7eeSOleksandr Andrushchenko 	ret = xenbus_transaction_end(xbt, 0);
306c575b7eeSOleksandr Andrushchenko 	if (ret < 0) {
307c575b7eeSOleksandr Andrushchenko 		if (ret == -EAGAIN)
308c575b7eeSOleksandr Andrushchenko 			goto again;
309c575b7eeSOleksandr Andrushchenko 
310c575b7eeSOleksandr Andrushchenko 		xenbus_dev_fatal(front_info->xb_dev, ret,
311c575b7eeSOleksandr Andrushchenko 				 "completing transaction");
312c575b7eeSOleksandr Andrushchenko 		goto fail_to_end;
313c575b7eeSOleksandr Andrushchenko 	}
314c575b7eeSOleksandr Andrushchenko 
315c575b7eeSOleksandr Andrushchenko 	return 0;
316c575b7eeSOleksandr Andrushchenko 
317c575b7eeSOleksandr Andrushchenko fail:
318c575b7eeSOleksandr Andrushchenko 	xenbus_transaction_end(xbt, 1);
319c575b7eeSOleksandr Andrushchenko 
320c575b7eeSOleksandr Andrushchenko fail_to_end:
321c575b7eeSOleksandr Andrushchenko 	xenbus_dev_fatal(front_info->xb_dev, ret, "writing Xen store");
322c575b7eeSOleksandr Andrushchenko 	return ret;
323c575b7eeSOleksandr Andrushchenko }
324c575b7eeSOleksandr Andrushchenko 
xen_drm_front_evtchnl_flush(struct xen_drm_front_evtchnl * evtchnl)325c575b7eeSOleksandr Andrushchenko void xen_drm_front_evtchnl_flush(struct xen_drm_front_evtchnl *evtchnl)
326c575b7eeSOleksandr Andrushchenko {
327c575b7eeSOleksandr Andrushchenko 	int notify;
328c575b7eeSOleksandr Andrushchenko 
329c575b7eeSOleksandr Andrushchenko 	evtchnl->u.req.ring.req_prod_pvt++;
330c575b7eeSOleksandr Andrushchenko 	RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&evtchnl->u.req.ring, notify);
331c575b7eeSOleksandr Andrushchenko 	if (notify)
332c575b7eeSOleksandr Andrushchenko 		notify_remote_via_irq(evtchnl->irq);
333c575b7eeSOleksandr Andrushchenko }
334c575b7eeSOleksandr Andrushchenko 
xen_drm_front_evtchnl_set_state(struct xen_drm_front_info * front_info,enum xen_drm_front_evtchnl_state state)335c575b7eeSOleksandr Andrushchenko void xen_drm_front_evtchnl_set_state(struct xen_drm_front_info *front_info,
336c575b7eeSOleksandr Andrushchenko 				     enum xen_drm_front_evtchnl_state state)
337c575b7eeSOleksandr Andrushchenko {
338c575b7eeSOleksandr Andrushchenko 	unsigned long flags;
339c575b7eeSOleksandr Andrushchenko 	int i;
340c575b7eeSOleksandr Andrushchenko 
341c575b7eeSOleksandr Andrushchenko 	if (!front_info->evt_pairs)
342c575b7eeSOleksandr Andrushchenko 		return;
343c575b7eeSOleksandr Andrushchenko 
344c575b7eeSOleksandr Andrushchenko 	spin_lock_irqsave(&front_info->io_lock, flags);
345c575b7eeSOleksandr Andrushchenko 	for (i = 0; i < front_info->num_evt_pairs; i++) {
346c575b7eeSOleksandr Andrushchenko 		front_info->evt_pairs[i].req.state = state;
347c575b7eeSOleksandr Andrushchenko 		front_info->evt_pairs[i].evt.state = state;
348c575b7eeSOleksandr Andrushchenko 	}
349c575b7eeSOleksandr Andrushchenko 	spin_unlock_irqrestore(&front_info->io_lock, flags);
350c575b7eeSOleksandr Andrushchenko }
351c575b7eeSOleksandr Andrushchenko 
xen_drm_front_evtchnl_free_all(struct xen_drm_front_info * front_info)352c575b7eeSOleksandr Andrushchenko void xen_drm_front_evtchnl_free_all(struct xen_drm_front_info *front_info)
353c575b7eeSOleksandr Andrushchenko {
354c575b7eeSOleksandr Andrushchenko 	int i;
355c575b7eeSOleksandr Andrushchenko 
356c575b7eeSOleksandr Andrushchenko 	if (!front_info->evt_pairs)
357c575b7eeSOleksandr Andrushchenko 		return;
358c575b7eeSOleksandr Andrushchenko 
359c575b7eeSOleksandr Andrushchenko 	for (i = 0; i < front_info->num_evt_pairs; i++) {
360c575b7eeSOleksandr Andrushchenko 		evtchnl_free(front_info, &front_info->evt_pairs[i].req);
361c575b7eeSOleksandr Andrushchenko 		evtchnl_free(front_info, &front_info->evt_pairs[i].evt);
362c575b7eeSOleksandr Andrushchenko 	}
363c575b7eeSOleksandr Andrushchenko 
364c575b7eeSOleksandr Andrushchenko 	kfree(front_info->evt_pairs);
365c575b7eeSOleksandr Andrushchenko 	front_info->evt_pairs = NULL;
366c575b7eeSOleksandr Andrushchenko }
367