Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/xen/xen_snd_front_evtchnl.c
26378 views
1
// SPDX-License-Identifier: GPL-2.0 OR MIT
2
3
/*
4
* Xen para-virtual sound device
5
*
6
* Copyright (C) 2016-2018 EPAM Systems Inc.
7
*
8
* Author: Oleksandr Andrushchenko <[email protected]>
9
*/
10
11
#include <xen/events.h>
12
#include <xen/grant_table.h>
13
#include <xen/xen.h>
14
#include <xen/xenbus.h>
15
16
#include "xen_snd_front.h"
17
#include "xen_snd_front_alsa.h"
18
#include "xen_snd_front_cfg.h"
19
#include "xen_snd_front_evtchnl.h"
20
21
static irqreturn_t evtchnl_interrupt_req(int irq, void *dev_id)
22
{
23
struct xen_snd_front_evtchnl *channel = dev_id;
24
struct xen_snd_front_info *front_info = channel->front_info;
25
struct xensnd_resp *resp;
26
RING_IDX i, rp;
27
28
if (unlikely(channel->state != EVTCHNL_STATE_CONNECTED))
29
return IRQ_HANDLED;
30
31
mutex_lock(&channel->ring_io_lock);
32
33
again:
34
rp = channel->u.req.ring.sring->rsp_prod;
35
/* Ensure we see queued responses up to rp. */
36
rmb();
37
38
/*
39
* Assume that the backend is trusted to always write sane values
40
* to the ring counters, so no overflow checks on frontend side
41
* are required.
42
*/
43
for (i = channel->u.req.ring.rsp_cons; i != rp; i++) {
44
resp = RING_GET_RESPONSE(&channel->u.req.ring, i);
45
if (resp->id != channel->evt_id)
46
continue;
47
switch (resp->operation) {
48
case XENSND_OP_OPEN:
49
case XENSND_OP_CLOSE:
50
case XENSND_OP_READ:
51
case XENSND_OP_WRITE:
52
case XENSND_OP_TRIGGER:
53
channel->u.req.resp_status = resp->status;
54
complete(&channel->u.req.completion);
55
break;
56
case XENSND_OP_HW_PARAM_QUERY:
57
channel->u.req.resp_status = resp->status;
58
channel->u.req.resp.hw_param =
59
resp->resp.hw_param;
60
complete(&channel->u.req.completion);
61
break;
62
63
default:
64
dev_err(&front_info->xb_dev->dev,
65
"Operation %d is not supported\n",
66
resp->operation);
67
break;
68
}
69
}
70
71
channel->u.req.ring.rsp_cons = i;
72
if (i != channel->u.req.ring.req_prod_pvt) {
73
int more_to_do;
74
75
RING_FINAL_CHECK_FOR_RESPONSES(&channel->u.req.ring,
76
more_to_do);
77
if (more_to_do)
78
goto again;
79
} else {
80
channel->u.req.ring.sring->rsp_event = i + 1;
81
}
82
83
mutex_unlock(&channel->ring_io_lock);
84
return IRQ_HANDLED;
85
}
86
87
static irqreturn_t evtchnl_interrupt_evt(int irq, void *dev_id)
88
{
89
struct xen_snd_front_evtchnl *channel = dev_id;
90
struct xensnd_event_page *page = channel->u.evt.page;
91
u32 cons, prod;
92
93
if (unlikely(channel->state != EVTCHNL_STATE_CONNECTED))
94
return IRQ_HANDLED;
95
96
mutex_lock(&channel->ring_io_lock);
97
98
prod = page->in_prod;
99
/* Ensure we see ring contents up to prod. */
100
virt_rmb();
101
if (prod == page->in_cons)
102
goto out;
103
104
/*
105
* Assume that the backend is trusted to always write sane values
106
* to the ring counters, so no overflow checks on frontend side
107
* are required.
108
*/
109
for (cons = page->in_cons; cons != prod; cons++) {
110
struct xensnd_evt *event;
111
112
event = &XENSND_IN_RING_REF(page, cons);
113
if (unlikely(event->id != channel->evt_id++))
114
continue;
115
116
switch (event->type) {
117
case XENSND_EVT_CUR_POS:
118
xen_snd_front_alsa_handle_cur_pos(channel,
119
event->op.cur_pos.position);
120
break;
121
}
122
}
123
124
page->in_cons = cons;
125
/* Ensure ring contents. */
126
virt_wmb();
127
128
out:
129
mutex_unlock(&channel->ring_io_lock);
130
return IRQ_HANDLED;
131
}
132
133
void xen_snd_front_evtchnl_flush(struct xen_snd_front_evtchnl *channel)
134
{
135
int notify;
136
137
channel->u.req.ring.req_prod_pvt++;
138
RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&channel->u.req.ring, notify);
139
if (notify)
140
notify_remote_via_irq(channel->irq);
141
}
142
143
static void evtchnl_free(struct xen_snd_front_info *front_info,
144
struct xen_snd_front_evtchnl *channel)
145
{
146
void *page = NULL;
147
148
if (channel->type == EVTCHNL_TYPE_REQ)
149
page = channel->u.req.ring.sring;
150
else if (channel->type == EVTCHNL_TYPE_EVT)
151
page = channel->u.evt.page;
152
153
if (!page)
154
return;
155
156
channel->state = EVTCHNL_STATE_DISCONNECTED;
157
if (channel->type == EVTCHNL_TYPE_REQ) {
158
/* Release all who still waits for response if any. */
159
channel->u.req.resp_status = -EIO;
160
complete_all(&channel->u.req.completion);
161
}
162
163
if (channel->irq)
164
unbind_from_irqhandler(channel->irq, channel);
165
166
if (channel->port)
167
xenbus_free_evtchn(front_info->xb_dev, channel->port);
168
169
/* End access and free the page. */
170
xenbus_teardown_ring(&page, 1, &channel->gref);
171
172
memset(channel, 0, sizeof(*channel));
173
}
174
175
void xen_snd_front_evtchnl_free_all(struct xen_snd_front_info *front_info)
176
{
177
int i;
178
179
if (!front_info->evt_pairs)
180
return;
181
182
for (i = 0; i < front_info->num_evt_pairs; i++) {
183
evtchnl_free(front_info, &front_info->evt_pairs[i].req);
184
evtchnl_free(front_info, &front_info->evt_pairs[i].evt);
185
}
186
187
kfree(front_info->evt_pairs);
188
front_info->evt_pairs = NULL;
189
}
190
191
static int evtchnl_alloc(struct xen_snd_front_info *front_info, int index,
192
struct xen_snd_front_evtchnl *channel,
193
enum xen_snd_front_evtchnl_type type)
194
{
195
struct xenbus_device *xb_dev = front_info->xb_dev;
196
void *page;
197
irq_handler_t handler;
198
char *handler_name = NULL;
199
int ret;
200
201
memset(channel, 0, sizeof(*channel));
202
channel->type = type;
203
channel->index = index;
204
channel->front_info = front_info;
205
channel->state = EVTCHNL_STATE_DISCONNECTED;
206
ret = xenbus_setup_ring(xb_dev, GFP_KERNEL, &page, 1, &channel->gref);
207
if (ret)
208
goto fail;
209
210
handler_name = kasprintf(GFP_KERNEL, "%s-%s", XENSND_DRIVER_NAME,
211
type == EVTCHNL_TYPE_REQ ?
212
XENSND_FIELD_RING_REF :
213
XENSND_FIELD_EVT_RING_REF);
214
if (!handler_name) {
215
ret = -ENOMEM;
216
goto fail;
217
}
218
219
mutex_init(&channel->ring_io_lock);
220
221
if (type == EVTCHNL_TYPE_REQ) {
222
struct xen_sndif_sring *sring = page;
223
224
init_completion(&channel->u.req.completion);
225
mutex_init(&channel->u.req.req_io_lock);
226
XEN_FRONT_RING_INIT(&channel->u.req.ring, sring, XEN_PAGE_SIZE);
227
228
handler = evtchnl_interrupt_req;
229
} else {
230
channel->u.evt.page = page;
231
handler = evtchnl_interrupt_evt;
232
}
233
234
ret = xenbus_alloc_evtchn(xb_dev, &channel->port);
235
if (ret < 0)
236
goto fail;
237
238
ret = bind_evtchn_to_irq(channel->port);
239
if (ret < 0) {
240
dev_err(&xb_dev->dev,
241
"Failed to bind IRQ for domid %d port %d: %d\n",
242
front_info->xb_dev->otherend_id, channel->port, ret);
243
goto fail;
244
}
245
246
channel->irq = ret;
247
248
ret = request_threaded_irq(channel->irq, NULL, handler,
249
IRQF_ONESHOT, handler_name, channel);
250
if (ret < 0) {
251
dev_err(&xb_dev->dev, "Failed to request IRQ %d: %d\n",
252
channel->irq, ret);
253
goto fail;
254
}
255
256
kfree(handler_name);
257
return 0;
258
259
fail:
260
kfree(handler_name);
261
dev_err(&xb_dev->dev, "Failed to allocate ring: %d\n", ret);
262
return ret;
263
}
264
265
int xen_snd_front_evtchnl_create_all(struct xen_snd_front_info *front_info,
266
int num_streams)
267
{
268
struct xen_front_cfg_card *cfg = &front_info->cfg;
269
struct device *dev = &front_info->xb_dev->dev;
270
int d, ret = 0;
271
272
front_info->evt_pairs =
273
kcalloc(num_streams,
274
sizeof(struct xen_snd_front_evtchnl_pair),
275
GFP_KERNEL);
276
if (!front_info->evt_pairs)
277
return -ENOMEM;
278
279
/* Iterate over devices and their streams and create event channels. */
280
for (d = 0; d < cfg->num_pcm_instances; d++) {
281
struct xen_front_cfg_pcm_instance *pcm_instance;
282
int s, index;
283
284
pcm_instance = &cfg->pcm_instances[d];
285
286
for (s = 0; s < pcm_instance->num_streams_pb; s++) {
287
index = pcm_instance->streams_pb[s].index;
288
289
ret = evtchnl_alloc(front_info, index,
290
&front_info->evt_pairs[index].req,
291
EVTCHNL_TYPE_REQ);
292
if (ret < 0) {
293
dev_err(dev, "Error allocating control channel\n");
294
goto fail;
295
}
296
297
ret = evtchnl_alloc(front_info, index,
298
&front_info->evt_pairs[index].evt,
299
EVTCHNL_TYPE_EVT);
300
if (ret < 0) {
301
dev_err(dev, "Error allocating in-event channel\n");
302
goto fail;
303
}
304
}
305
306
for (s = 0; s < pcm_instance->num_streams_cap; s++) {
307
index = pcm_instance->streams_cap[s].index;
308
309
ret = evtchnl_alloc(front_info, index,
310
&front_info->evt_pairs[index].req,
311
EVTCHNL_TYPE_REQ);
312
if (ret < 0) {
313
dev_err(dev, "Error allocating control channel\n");
314
goto fail;
315
}
316
317
ret = evtchnl_alloc(front_info, index,
318
&front_info->evt_pairs[index].evt,
319
EVTCHNL_TYPE_EVT);
320
if (ret < 0) {
321
dev_err(dev, "Error allocating in-event channel\n");
322
goto fail;
323
}
324
}
325
}
326
327
front_info->num_evt_pairs = num_streams;
328
return 0;
329
330
fail:
331
xen_snd_front_evtchnl_free_all(front_info);
332
return ret;
333
}
334
335
static int evtchnl_publish(struct xenbus_transaction xbt,
336
struct xen_snd_front_evtchnl *channel,
337
const char *path, const char *node_ring,
338
const char *node_chnl)
339
{
340
struct xenbus_device *xb_dev = channel->front_info->xb_dev;
341
int ret;
342
343
/* Write control channel ring reference. */
344
ret = xenbus_printf(xbt, path, node_ring, "%u", channel->gref);
345
if (ret < 0) {
346
dev_err(&xb_dev->dev, "Error writing ring-ref: %d\n", ret);
347
return ret;
348
}
349
350
/* Write event channel ring reference. */
351
ret = xenbus_printf(xbt, path, node_chnl, "%u", channel->port);
352
if (ret < 0) {
353
dev_err(&xb_dev->dev, "Error writing event channel: %d\n", ret);
354
return ret;
355
}
356
357
return 0;
358
}
359
360
int xen_snd_front_evtchnl_publish_all(struct xen_snd_front_info *front_info)
361
{
362
struct xen_front_cfg_card *cfg = &front_info->cfg;
363
struct xenbus_transaction xbt;
364
int ret, d;
365
366
again:
367
ret = xenbus_transaction_start(&xbt);
368
if (ret < 0) {
369
xenbus_dev_fatal(front_info->xb_dev, ret,
370
"starting transaction");
371
return ret;
372
}
373
374
for (d = 0; d < cfg->num_pcm_instances; d++) {
375
struct xen_front_cfg_pcm_instance *pcm_instance;
376
int s, index;
377
378
pcm_instance = &cfg->pcm_instances[d];
379
380
for (s = 0; s < pcm_instance->num_streams_pb; s++) {
381
index = pcm_instance->streams_pb[s].index;
382
383
ret = evtchnl_publish(xbt,
384
&front_info->evt_pairs[index].req,
385
pcm_instance->streams_pb[s].xenstore_path,
386
XENSND_FIELD_RING_REF,
387
XENSND_FIELD_EVT_CHNL);
388
if (ret < 0)
389
goto fail;
390
391
ret = evtchnl_publish(xbt,
392
&front_info->evt_pairs[index].evt,
393
pcm_instance->streams_pb[s].xenstore_path,
394
XENSND_FIELD_EVT_RING_REF,
395
XENSND_FIELD_EVT_EVT_CHNL);
396
if (ret < 0)
397
goto fail;
398
}
399
400
for (s = 0; s < pcm_instance->num_streams_cap; s++) {
401
index = pcm_instance->streams_cap[s].index;
402
403
ret = evtchnl_publish(xbt,
404
&front_info->evt_pairs[index].req,
405
pcm_instance->streams_cap[s].xenstore_path,
406
XENSND_FIELD_RING_REF,
407
XENSND_FIELD_EVT_CHNL);
408
if (ret < 0)
409
goto fail;
410
411
ret = evtchnl_publish(xbt,
412
&front_info->evt_pairs[index].evt,
413
pcm_instance->streams_cap[s].xenstore_path,
414
XENSND_FIELD_EVT_RING_REF,
415
XENSND_FIELD_EVT_EVT_CHNL);
416
if (ret < 0)
417
goto fail;
418
}
419
}
420
ret = xenbus_transaction_end(xbt, 0);
421
if (ret < 0) {
422
if (ret == -EAGAIN)
423
goto again;
424
425
xenbus_dev_fatal(front_info->xb_dev, ret,
426
"completing transaction");
427
goto fail_to_end;
428
}
429
return 0;
430
fail:
431
xenbus_transaction_end(xbt, 1);
432
fail_to_end:
433
xenbus_dev_fatal(front_info->xb_dev, ret, "writing XenStore");
434
return ret;
435
}
436
437
void xen_snd_front_evtchnl_pair_set_connected(struct xen_snd_front_evtchnl_pair *evt_pair,
438
bool is_connected)
439
{
440
enum xen_snd_front_evtchnl_state state;
441
442
if (is_connected)
443
state = EVTCHNL_STATE_CONNECTED;
444
else
445
state = EVTCHNL_STATE_DISCONNECTED;
446
447
mutex_lock(&evt_pair->req.ring_io_lock);
448
evt_pair->req.state = state;
449
mutex_unlock(&evt_pair->req.ring_io_lock);
450
451
mutex_lock(&evt_pair->evt.ring_io_lock);
452
evt_pair->evt.state = state;
453
mutex_unlock(&evt_pair->evt.ring_io_lock);
454
}
455
456
void xen_snd_front_evtchnl_pair_clear(struct xen_snd_front_evtchnl_pair *evt_pair)
457
{
458
mutex_lock(&evt_pair->req.ring_io_lock);
459
evt_pair->req.evt_next_id = 0;
460
mutex_unlock(&evt_pair->req.ring_io_lock);
461
462
mutex_lock(&evt_pair->evt.ring_io_lock);
463
evt_pair->evt.evt_next_id = 0;
464
mutex_unlock(&evt_pair->evt.ring_io_lock);
465
}
466
467
468