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