xref: /openbmc/linux/sound/virtio/virtio_card.c (revision d9679d00)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * virtio-snd: Virtio sound device
4  * Copyright (C) 2021 OpenSynergy GmbH
5  */
6 #include <linux/module.h>
7 #include <linux/moduleparam.h>
8 #include <linux/virtio_config.h>
9 #include <sound/initval.h>
10 #include <uapi/linux/virtio_ids.h>
11 
12 #include "virtio_card.h"
13 
14 u32 virtsnd_msg_timeout_ms = MSEC_PER_SEC;
15 module_param_named(msg_timeout_ms, virtsnd_msg_timeout_ms, uint, 0644);
16 MODULE_PARM_DESC(msg_timeout_ms, "Message completion timeout in milliseconds");
17 
18 static void virtsnd_remove(struct virtio_device *vdev);
19 
20 /**
21  * virtsnd_event_send() - Add an event to the event queue.
22  * @vqueue: Underlying event virtqueue.
23  * @event: Event.
24  * @notify: Indicates whether or not to send a notification to the device.
25  * @gfp: Kernel flags for memory allocation.
26  *
27  * Context: Any context.
28  */
virtsnd_event_send(struct virtqueue * vqueue,struct virtio_snd_event * event,bool notify,gfp_t gfp)29 static void virtsnd_event_send(struct virtqueue *vqueue,
30 			       struct virtio_snd_event *event, bool notify,
31 			       gfp_t gfp)
32 {
33 	struct scatterlist sg;
34 	struct scatterlist *psgs[1] = { &sg };
35 
36 	/* reset event content */
37 	memset(event, 0, sizeof(*event));
38 
39 	sg_init_one(&sg, event, sizeof(*event));
40 
41 	if (virtqueue_add_sgs(vqueue, psgs, 0, 1, event, gfp) || !notify)
42 		return;
43 
44 	if (virtqueue_kick_prepare(vqueue))
45 		virtqueue_notify(vqueue);
46 }
47 
48 /**
49  * virtsnd_event_dispatch() - Dispatch an event from the device side.
50  * @snd: VirtIO sound device.
51  * @event: VirtIO sound event.
52  *
53  * Context: Any context.
54  */
virtsnd_event_dispatch(struct virtio_snd * snd,struct virtio_snd_event * event)55 static void virtsnd_event_dispatch(struct virtio_snd *snd,
56 				   struct virtio_snd_event *event)
57 {
58 	switch (le32_to_cpu(event->hdr.code)) {
59 	case VIRTIO_SND_EVT_JACK_CONNECTED:
60 	case VIRTIO_SND_EVT_JACK_DISCONNECTED:
61 		virtsnd_jack_event(snd, event);
62 		break;
63 	case VIRTIO_SND_EVT_PCM_PERIOD_ELAPSED:
64 	case VIRTIO_SND_EVT_PCM_XRUN:
65 		virtsnd_pcm_event(snd, event);
66 		break;
67 	}
68 }
69 
70 /**
71  * virtsnd_event_notify_cb() - Dispatch all reported events from the event queue.
72  * @vqueue: Underlying event virtqueue.
73  *
74  * This callback function is called upon a vring interrupt request from the
75  * device.
76  *
77  * Context: Interrupt context.
78  */
virtsnd_event_notify_cb(struct virtqueue * vqueue)79 static void virtsnd_event_notify_cb(struct virtqueue *vqueue)
80 {
81 	struct virtio_snd *snd = vqueue->vdev->priv;
82 	struct virtio_snd_queue *queue = virtsnd_event_queue(snd);
83 	struct virtio_snd_event *event;
84 	u32 length;
85 	unsigned long flags;
86 
87 	spin_lock_irqsave(&queue->lock, flags);
88 	do {
89 		virtqueue_disable_cb(vqueue);
90 		while ((event = virtqueue_get_buf(vqueue, &length))) {
91 			virtsnd_event_dispatch(snd, event);
92 			virtsnd_event_send(vqueue, event, true, GFP_ATOMIC);
93 		}
94 		if (unlikely(virtqueue_is_broken(vqueue)))
95 			break;
96 	} while (!virtqueue_enable_cb(vqueue));
97 	spin_unlock_irqrestore(&queue->lock, flags);
98 }
99 
100 /**
101  * virtsnd_find_vqs() - Enumerate and initialize all virtqueues.
102  * @snd: VirtIO sound device.
103  *
104  * After calling this function, the event queue is disabled.
105  *
106  * Context: Any context.
107  * Return: 0 on success, -errno on failure.
108  */
virtsnd_find_vqs(struct virtio_snd * snd)109 static int virtsnd_find_vqs(struct virtio_snd *snd)
110 {
111 	struct virtio_device *vdev = snd->vdev;
112 	static vq_callback_t *callbacks[VIRTIO_SND_VQ_MAX] = {
113 		[VIRTIO_SND_VQ_CONTROL] = virtsnd_ctl_notify_cb,
114 		[VIRTIO_SND_VQ_EVENT] = virtsnd_event_notify_cb,
115 		[VIRTIO_SND_VQ_TX] = virtsnd_pcm_tx_notify_cb,
116 		[VIRTIO_SND_VQ_RX] = virtsnd_pcm_rx_notify_cb
117 	};
118 	static const char *names[VIRTIO_SND_VQ_MAX] = {
119 		[VIRTIO_SND_VQ_CONTROL] = "virtsnd-ctl",
120 		[VIRTIO_SND_VQ_EVENT] = "virtsnd-event",
121 		[VIRTIO_SND_VQ_TX] = "virtsnd-tx",
122 		[VIRTIO_SND_VQ_RX] = "virtsnd-rx"
123 	};
124 	struct virtqueue *vqs[VIRTIO_SND_VQ_MAX] = { 0 };
125 	unsigned int i;
126 	unsigned int n;
127 	int rc;
128 
129 	rc = virtio_find_vqs(vdev, VIRTIO_SND_VQ_MAX, vqs, callbacks, names,
130 			     NULL);
131 	if (rc) {
132 		dev_err(&vdev->dev, "failed to initialize virtqueues\n");
133 		return rc;
134 	}
135 
136 	for (i = 0; i < VIRTIO_SND_VQ_MAX; ++i)
137 		snd->queues[i].vqueue = vqs[i];
138 
139 	/* Allocate events and populate the event queue */
140 	virtqueue_disable_cb(vqs[VIRTIO_SND_VQ_EVENT]);
141 
142 	n = virtqueue_get_vring_size(vqs[VIRTIO_SND_VQ_EVENT]);
143 
144 	snd->event_msgs = kmalloc_array(n, sizeof(*snd->event_msgs),
145 					GFP_KERNEL);
146 	if (!snd->event_msgs)
147 		return -ENOMEM;
148 
149 	for (i = 0; i < n; ++i)
150 		virtsnd_event_send(vqs[VIRTIO_SND_VQ_EVENT],
151 				   &snd->event_msgs[i], false, GFP_KERNEL);
152 
153 	return 0;
154 }
155 
156 /**
157  * virtsnd_enable_event_vq() - Enable the event virtqueue.
158  * @snd: VirtIO sound device.
159  *
160  * Context: Any context.
161  */
virtsnd_enable_event_vq(struct virtio_snd * snd)162 static void virtsnd_enable_event_vq(struct virtio_snd *snd)
163 {
164 	struct virtio_snd_queue *queue = virtsnd_event_queue(snd);
165 
166 	if (!virtqueue_enable_cb(queue->vqueue))
167 		virtsnd_event_notify_cb(queue->vqueue);
168 }
169 
170 /**
171  * virtsnd_disable_event_vq() - Disable the event virtqueue.
172  * @snd: VirtIO sound device.
173  *
174  * Context: Any context.
175  */
virtsnd_disable_event_vq(struct virtio_snd * snd)176 static void virtsnd_disable_event_vq(struct virtio_snd *snd)
177 {
178 	struct virtio_snd_queue *queue = virtsnd_event_queue(snd);
179 	struct virtio_snd_event *event;
180 	u32 length;
181 	unsigned long flags;
182 
183 	if (queue->vqueue) {
184 		spin_lock_irqsave(&queue->lock, flags);
185 		virtqueue_disable_cb(queue->vqueue);
186 		while ((event = virtqueue_get_buf(queue->vqueue, &length)))
187 			virtsnd_event_dispatch(snd, event);
188 		spin_unlock_irqrestore(&queue->lock, flags);
189 	}
190 }
191 
192 /**
193  * virtsnd_build_devs() - Read configuration and build ALSA devices.
194  * @snd: VirtIO sound device.
195  *
196  * Context: Any context that permits to sleep.
197  * Return: 0 on success, -errno on failure.
198  */
virtsnd_build_devs(struct virtio_snd * snd)199 static int virtsnd_build_devs(struct virtio_snd *snd)
200 {
201 	struct virtio_device *vdev = snd->vdev;
202 	struct device *dev = &vdev->dev;
203 	int rc;
204 
205 	rc = snd_card_new(dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
206 			  THIS_MODULE, 0, &snd->card);
207 	if (rc < 0)
208 		return rc;
209 
210 	snd->card->private_data = snd;
211 
212 	strscpy(snd->card->driver, VIRTIO_SND_CARD_DRIVER,
213 		sizeof(snd->card->driver));
214 	strscpy(snd->card->shortname, VIRTIO_SND_CARD_NAME,
215 		sizeof(snd->card->shortname));
216 	if (dev->parent->bus)
217 		snprintf(snd->card->longname, sizeof(snd->card->longname),
218 			 VIRTIO_SND_CARD_NAME " at %s/%s/%s",
219 			 dev->parent->bus->name, dev_name(dev->parent),
220 			 dev_name(dev));
221 	else
222 		snprintf(snd->card->longname, sizeof(snd->card->longname),
223 			 VIRTIO_SND_CARD_NAME " at %s/%s",
224 			 dev_name(dev->parent), dev_name(dev));
225 
226 	rc = virtsnd_jack_parse_cfg(snd);
227 	if (rc)
228 		return rc;
229 
230 	rc = virtsnd_pcm_parse_cfg(snd);
231 	if (rc)
232 		return rc;
233 
234 	rc = virtsnd_chmap_parse_cfg(snd);
235 	if (rc)
236 		return rc;
237 
238 	if (snd->njacks) {
239 		rc = virtsnd_jack_build_devs(snd);
240 		if (rc)
241 			return rc;
242 	}
243 
244 	if (snd->nsubstreams) {
245 		rc = virtsnd_pcm_build_devs(snd);
246 		if (rc)
247 			return rc;
248 	}
249 
250 	if (snd->nchmaps) {
251 		rc = virtsnd_chmap_build_devs(snd);
252 		if (rc)
253 			return rc;
254 	}
255 
256 	return snd_card_register(snd->card);
257 }
258 
259 /**
260  * virtsnd_validate() - Validate if the device can be started.
261  * @vdev: VirtIO parent device.
262  *
263  * Context: Any context.
264  * Return: 0 on success, -EINVAL on failure.
265  */
virtsnd_validate(struct virtio_device * vdev)266 static int virtsnd_validate(struct virtio_device *vdev)
267 {
268 	if (!vdev->config->get) {
269 		dev_err(&vdev->dev, "configuration access disabled\n");
270 		return -EINVAL;
271 	}
272 
273 	if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) {
274 		dev_err(&vdev->dev,
275 			"device does not comply with spec version 1.x\n");
276 		return -EINVAL;
277 	}
278 
279 	if (!virtsnd_msg_timeout_ms) {
280 		dev_err(&vdev->dev, "msg_timeout_ms value cannot be zero\n");
281 		return -EINVAL;
282 	}
283 
284 	if (virtsnd_pcm_validate(vdev))
285 		return -EINVAL;
286 
287 	return 0;
288 }
289 
290 /**
291  * virtsnd_probe() - Create and initialize the device.
292  * @vdev: VirtIO parent device.
293  *
294  * Context: Any context that permits to sleep.
295  * Return: 0 on success, -errno on failure.
296  */
virtsnd_probe(struct virtio_device * vdev)297 static int virtsnd_probe(struct virtio_device *vdev)
298 {
299 	struct virtio_snd *snd;
300 	unsigned int i;
301 	int rc;
302 
303 	snd = devm_kzalloc(&vdev->dev, sizeof(*snd), GFP_KERNEL);
304 	if (!snd)
305 		return -ENOMEM;
306 
307 	snd->vdev = vdev;
308 	INIT_LIST_HEAD(&snd->ctl_msgs);
309 	INIT_LIST_HEAD(&snd->pcm_list);
310 
311 	vdev->priv = snd;
312 
313 	for (i = 0; i < VIRTIO_SND_VQ_MAX; ++i)
314 		spin_lock_init(&snd->queues[i].lock);
315 
316 	rc = virtsnd_find_vqs(snd);
317 	if (rc)
318 		goto on_exit;
319 
320 	virtio_device_ready(vdev);
321 
322 	rc = virtsnd_build_devs(snd);
323 	if (rc)
324 		goto on_exit;
325 
326 	virtsnd_enable_event_vq(snd);
327 
328 on_exit:
329 	if (rc)
330 		virtsnd_remove(vdev);
331 
332 	return rc;
333 }
334 
335 /**
336  * virtsnd_remove() - Remove VirtIO and ALSA devices.
337  * @vdev: VirtIO parent device.
338  *
339  * Context: Any context that permits to sleep.
340  */
virtsnd_remove(struct virtio_device * vdev)341 static void virtsnd_remove(struct virtio_device *vdev)
342 {
343 	struct virtio_snd *snd = vdev->priv;
344 	unsigned int i;
345 
346 	virtsnd_disable_event_vq(snd);
347 	virtsnd_ctl_msg_cancel_all(snd);
348 
349 	if (snd->card)
350 		snd_card_free(snd->card);
351 
352 	vdev->config->del_vqs(vdev);
353 	virtio_reset_device(vdev);
354 
355 	for (i = 0; snd->substreams && i < snd->nsubstreams; ++i) {
356 		struct virtio_pcm_substream *vss = &snd->substreams[i];
357 
358 		cancel_work_sync(&vss->elapsed_period);
359 		virtsnd_pcm_msg_free(vss);
360 	}
361 
362 	kfree(snd->event_msgs);
363 }
364 
365 #ifdef CONFIG_PM_SLEEP
366 /**
367  * virtsnd_freeze() - Suspend device.
368  * @vdev: VirtIO parent device.
369  *
370  * Context: Any context.
371  * Return: 0 on success, -errno on failure.
372  */
virtsnd_freeze(struct virtio_device * vdev)373 static int virtsnd_freeze(struct virtio_device *vdev)
374 {
375 	struct virtio_snd *snd = vdev->priv;
376 	unsigned int i;
377 
378 	virtsnd_disable_event_vq(snd);
379 	virtsnd_ctl_msg_cancel_all(snd);
380 
381 	vdev->config->del_vqs(vdev);
382 	virtio_reset_device(vdev);
383 
384 	for (i = 0; i < snd->nsubstreams; ++i)
385 		cancel_work_sync(&snd->substreams[i].elapsed_period);
386 
387 	kfree(snd->event_msgs);
388 	snd->event_msgs = NULL;
389 
390 	return 0;
391 }
392 
393 /**
394  * virtsnd_restore() - Resume device.
395  * @vdev: VirtIO parent device.
396  *
397  * Context: Any context.
398  * Return: 0 on success, -errno on failure.
399  */
virtsnd_restore(struct virtio_device * vdev)400 static int virtsnd_restore(struct virtio_device *vdev)
401 {
402 	struct virtio_snd *snd = vdev->priv;
403 	int rc;
404 
405 	rc = virtsnd_find_vqs(snd);
406 	if (rc)
407 		return rc;
408 
409 	virtio_device_ready(vdev);
410 
411 	virtsnd_enable_event_vq(snd);
412 
413 	return 0;
414 }
415 #endif /* CONFIG_PM_SLEEP */
416 
417 static const struct virtio_device_id id_table[] = {
418 	{ VIRTIO_ID_SOUND, VIRTIO_DEV_ANY_ID },
419 	{ 0 },
420 };
421 
422 static struct virtio_driver virtsnd_driver = {
423 	.driver.name = KBUILD_MODNAME,
424 	.driver.owner = THIS_MODULE,
425 	.id_table = id_table,
426 	.validate = virtsnd_validate,
427 	.probe = virtsnd_probe,
428 	.remove = virtsnd_remove,
429 #ifdef CONFIG_PM_SLEEP
430 	.freeze = virtsnd_freeze,
431 	.restore = virtsnd_restore,
432 #endif
433 };
434 
435 module_virtio_driver(virtsnd_driver);
436 
437 MODULE_DEVICE_TABLE(virtio, id_table);
438 MODULE_DESCRIPTION("Virtio sound card driver");
439 MODULE_LICENSE("GPL");
440