cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

virtio_card.c (10337B)


      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
     14u32 virtsnd_msg_timeout_ms = MSEC_PER_SEC;
     15module_param_named(msg_timeout_ms, virtsnd_msg_timeout_ms, uint, 0644);
     16MODULE_PARM_DESC(msg_timeout_ms, "Message completion timeout in milliseconds");
     17
     18static 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 */
     29static 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 */
     55static 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 */
     79static 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 */
    109static 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 */
    162static 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 */
    176static 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 */
    199static 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 */
    266static 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 */
    297static 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
    328on_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 */
    341static 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 */
    373static 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 */
    400static 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
    417static const struct virtio_device_id id_table[] = {
    418	{ VIRTIO_ID_SOUND, VIRTIO_DEV_ANY_ID },
    419	{ 0 },
    420};
    421
    422static 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
    435module_virtio_driver(virtsnd_driver);
    436
    437MODULE_DEVICE_TABLE(virtio, id_table);
    438MODULE_DESCRIPTION("Virtio sound card driver");
    439MODULE_LICENSE("GPL");