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_pcm_ops.c (13844B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * virtio-snd: Virtio sound device
      4 * Copyright (C) 2021 OpenSynergy GmbH
      5 */
      6#include <sound/pcm_params.h>
      7
      8#include "virtio_card.h"
      9
     10/*
     11 * I/O messages lifetime
     12 * ---------------------
     13 *
     14 * Allocation:
     15 *   Messages are initially allocated in the ops->hw_params() after the size and
     16 *   number of periods have been successfully negotiated.
     17 *
     18 * Freeing:
     19 *   Messages can be safely freed after the queue has been successfully flushed
     20 *   (RELEASE command in the ops->sync_stop()) and the ops->hw_free() has been
     21 *   called.
     22 *
     23 *   When the substream stops, the ops->sync_stop() waits until the device has
     24 *   completed all pending messages. This wait can be interrupted either by a
     25 *   signal or due to a timeout. In this case, the device can still access
     26 *   messages even after calling ops->hw_free(). It can also issue an interrupt,
     27 *   and the interrupt handler will also try to access message structures.
     28 *
     29 *   Therefore, freeing of already allocated messages occurs:
     30 *
     31 *   - in ops->hw_params(), if this operator was called several times in a row,
     32 *     or if ops->hw_free() failed to free messages previously;
     33 *
     34 *   - in ops->hw_free(), if the queue has been successfully flushed;
     35 *
     36 *   - in dev->release().
     37 */
     38
     39/* Map for converting ALSA format to VirtIO format. */
     40struct virtsnd_a2v_format {
     41	snd_pcm_format_t alsa_bit;
     42	unsigned int vio_bit;
     43};
     44
     45static const struct virtsnd_a2v_format g_a2v_format_map[] = {
     46	{ SNDRV_PCM_FORMAT_IMA_ADPCM, VIRTIO_SND_PCM_FMT_IMA_ADPCM },
     47	{ SNDRV_PCM_FORMAT_MU_LAW, VIRTIO_SND_PCM_FMT_MU_LAW },
     48	{ SNDRV_PCM_FORMAT_A_LAW, VIRTIO_SND_PCM_FMT_A_LAW },
     49	{ SNDRV_PCM_FORMAT_S8, VIRTIO_SND_PCM_FMT_S8 },
     50	{ SNDRV_PCM_FORMAT_U8, VIRTIO_SND_PCM_FMT_U8 },
     51	{ SNDRV_PCM_FORMAT_S16_LE, VIRTIO_SND_PCM_FMT_S16 },
     52	{ SNDRV_PCM_FORMAT_U16_LE, VIRTIO_SND_PCM_FMT_U16 },
     53	{ SNDRV_PCM_FORMAT_S18_3LE, VIRTIO_SND_PCM_FMT_S18_3 },
     54	{ SNDRV_PCM_FORMAT_U18_3LE, VIRTIO_SND_PCM_FMT_U18_3 },
     55	{ SNDRV_PCM_FORMAT_S20_3LE, VIRTIO_SND_PCM_FMT_S20_3 },
     56	{ SNDRV_PCM_FORMAT_U20_3LE, VIRTIO_SND_PCM_FMT_U20_3 },
     57	{ SNDRV_PCM_FORMAT_S24_3LE, VIRTIO_SND_PCM_FMT_S24_3 },
     58	{ SNDRV_PCM_FORMAT_U24_3LE, VIRTIO_SND_PCM_FMT_U24_3 },
     59	{ SNDRV_PCM_FORMAT_S20_LE, VIRTIO_SND_PCM_FMT_S20 },
     60	{ SNDRV_PCM_FORMAT_U20_LE, VIRTIO_SND_PCM_FMT_U20 },
     61	{ SNDRV_PCM_FORMAT_S24_LE, VIRTIO_SND_PCM_FMT_S24 },
     62	{ SNDRV_PCM_FORMAT_U24_LE, VIRTIO_SND_PCM_FMT_U24 },
     63	{ SNDRV_PCM_FORMAT_S32_LE, VIRTIO_SND_PCM_FMT_S32 },
     64	{ SNDRV_PCM_FORMAT_U32_LE, VIRTIO_SND_PCM_FMT_U32 },
     65	{ SNDRV_PCM_FORMAT_FLOAT_LE, VIRTIO_SND_PCM_FMT_FLOAT },
     66	{ SNDRV_PCM_FORMAT_FLOAT64_LE, VIRTIO_SND_PCM_FMT_FLOAT64 },
     67	{ SNDRV_PCM_FORMAT_DSD_U8, VIRTIO_SND_PCM_FMT_DSD_U8 },
     68	{ SNDRV_PCM_FORMAT_DSD_U16_LE, VIRTIO_SND_PCM_FMT_DSD_U16 },
     69	{ SNDRV_PCM_FORMAT_DSD_U32_LE, VIRTIO_SND_PCM_FMT_DSD_U32 },
     70	{ SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE,
     71	  VIRTIO_SND_PCM_FMT_IEC958_SUBFRAME }
     72};
     73
     74/* Map for converting ALSA frame rate to VirtIO frame rate. */
     75struct virtsnd_a2v_rate {
     76	unsigned int rate;
     77	unsigned int vio_bit;
     78};
     79
     80static const struct virtsnd_a2v_rate g_a2v_rate_map[] = {
     81	{ 5512, VIRTIO_SND_PCM_RATE_5512 },
     82	{ 8000, VIRTIO_SND_PCM_RATE_8000 },
     83	{ 11025, VIRTIO_SND_PCM_RATE_11025 },
     84	{ 16000, VIRTIO_SND_PCM_RATE_16000 },
     85	{ 22050, VIRTIO_SND_PCM_RATE_22050 },
     86	{ 32000, VIRTIO_SND_PCM_RATE_32000 },
     87	{ 44100, VIRTIO_SND_PCM_RATE_44100 },
     88	{ 48000, VIRTIO_SND_PCM_RATE_48000 },
     89	{ 64000, VIRTIO_SND_PCM_RATE_64000 },
     90	{ 88200, VIRTIO_SND_PCM_RATE_88200 },
     91	{ 96000, VIRTIO_SND_PCM_RATE_96000 },
     92	{ 176400, VIRTIO_SND_PCM_RATE_176400 },
     93	{ 192000, VIRTIO_SND_PCM_RATE_192000 }
     94};
     95
     96static int virtsnd_pcm_sync_stop(struct snd_pcm_substream *substream);
     97
     98/**
     99 * virtsnd_pcm_open() - Open the PCM substream.
    100 * @substream: Kernel ALSA substream.
    101 *
    102 * Context: Process context.
    103 * Return: 0 on success, -errno on failure.
    104 */
    105static int virtsnd_pcm_open(struct snd_pcm_substream *substream)
    106{
    107	struct virtio_pcm *vpcm = snd_pcm_substream_chip(substream);
    108	struct virtio_pcm_stream *vs = &vpcm->streams[substream->stream];
    109	struct virtio_pcm_substream *vss = vs->substreams[substream->number];
    110
    111	substream->runtime->hw = vss->hw;
    112	substream->private_data = vss;
    113
    114	snd_pcm_hw_constraint_integer(substream->runtime,
    115				      SNDRV_PCM_HW_PARAM_PERIODS);
    116
    117	vss->stopped = !!virtsnd_pcm_msg_pending_num(vss);
    118	vss->suspended = false;
    119
    120	/*
    121	 * If the substream has already been used, then the I/O queue may be in
    122	 * an invalid state. Just in case, we do a check and try to return the
    123	 * queue to its original state, if necessary.
    124	 */
    125	return virtsnd_pcm_sync_stop(substream);
    126}
    127
    128/**
    129 * virtsnd_pcm_close() - Close the PCM substream.
    130 * @substream: Kernel ALSA substream.
    131 *
    132 * Context: Process context.
    133 * Return: 0.
    134 */
    135static int virtsnd_pcm_close(struct snd_pcm_substream *substream)
    136{
    137	return 0;
    138}
    139
    140/**
    141 * virtsnd_pcm_dev_set_params() - Set the parameters of the PCM substream on
    142 *                                the device side.
    143 * @vss: VirtIO PCM substream.
    144 * @buffer_bytes: Size of the hardware buffer.
    145 * @period_bytes: Size of the hardware period.
    146 * @channels: Selected number of channels.
    147 * @format: Selected sample format (SNDRV_PCM_FORMAT_XXX).
    148 * @rate: Selected frame rate.
    149 *
    150 * Context: Any context that permits to sleep.
    151 * Return: 0 on success, -errno on failure.
    152 */
    153static int virtsnd_pcm_dev_set_params(struct virtio_pcm_substream *vss,
    154				      unsigned int buffer_bytes,
    155				      unsigned int period_bytes,
    156				      unsigned int channels,
    157				      snd_pcm_format_t format,
    158				      unsigned int rate)
    159{
    160	struct virtio_snd_msg *msg;
    161	struct virtio_snd_pcm_set_params *request;
    162	unsigned int i;
    163	int vformat = -1;
    164	int vrate = -1;
    165
    166	for (i = 0; i < ARRAY_SIZE(g_a2v_format_map); ++i)
    167		if (g_a2v_format_map[i].alsa_bit == format) {
    168			vformat = g_a2v_format_map[i].vio_bit;
    169
    170			break;
    171		}
    172
    173	for (i = 0; i < ARRAY_SIZE(g_a2v_rate_map); ++i)
    174		if (g_a2v_rate_map[i].rate == rate) {
    175			vrate = g_a2v_rate_map[i].vio_bit;
    176
    177			break;
    178		}
    179
    180	if (vformat == -1 || vrate == -1)
    181		return -EINVAL;
    182
    183	msg = virtsnd_pcm_ctl_msg_alloc(vss, VIRTIO_SND_R_PCM_SET_PARAMS,
    184					GFP_KERNEL);
    185	if (!msg)
    186		return -ENOMEM;
    187
    188	request = virtsnd_ctl_msg_request(msg);
    189	request->buffer_bytes = cpu_to_le32(buffer_bytes);
    190	request->period_bytes = cpu_to_le32(period_bytes);
    191	request->channels = channels;
    192	request->format = vformat;
    193	request->rate = vrate;
    194
    195	if (vss->features & (1U << VIRTIO_SND_PCM_F_MSG_POLLING))
    196		request->features |=
    197			cpu_to_le32(1U << VIRTIO_SND_PCM_F_MSG_POLLING);
    198
    199	if (vss->features & (1U << VIRTIO_SND_PCM_F_EVT_XRUNS))
    200		request->features |=
    201			cpu_to_le32(1U << VIRTIO_SND_PCM_F_EVT_XRUNS);
    202
    203	return virtsnd_ctl_msg_send_sync(vss->snd, msg);
    204}
    205
    206/**
    207 * virtsnd_pcm_hw_params() - Set the parameters of the PCM substream.
    208 * @substream: Kernel ALSA substream.
    209 * @hw_params: Hardware parameters.
    210 *
    211 * Context: Process context.
    212 * Return: 0 on success, -errno on failure.
    213 */
    214static int virtsnd_pcm_hw_params(struct snd_pcm_substream *substream,
    215				 struct snd_pcm_hw_params *hw_params)
    216{
    217	struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream);
    218	struct virtio_device *vdev = vss->snd->vdev;
    219	int rc;
    220
    221	if (virtsnd_pcm_msg_pending_num(vss)) {
    222		dev_err(&vdev->dev, "SID %u: invalid I/O queue state\n",
    223			vss->sid);
    224		return -EBADFD;
    225	}
    226
    227	rc = virtsnd_pcm_dev_set_params(vss, params_buffer_bytes(hw_params),
    228					params_period_bytes(hw_params),
    229					params_channels(hw_params),
    230					params_format(hw_params),
    231					params_rate(hw_params));
    232	if (rc)
    233		return rc;
    234
    235	/*
    236	 * Free previously allocated messages if ops->hw_params() is called
    237	 * several times in a row, or if ops->hw_free() failed to free messages.
    238	 */
    239	virtsnd_pcm_msg_free(vss);
    240
    241	return virtsnd_pcm_msg_alloc(vss, params_periods(hw_params),
    242				     params_period_bytes(hw_params));
    243}
    244
    245/**
    246 * virtsnd_pcm_hw_free() - Reset the parameters of the PCM substream.
    247 * @substream: Kernel ALSA substream.
    248 *
    249 * Context: Process context.
    250 * Return: 0
    251 */
    252static int virtsnd_pcm_hw_free(struct snd_pcm_substream *substream)
    253{
    254	struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream);
    255
    256	/* If the queue is flushed, we can safely free the messages here. */
    257	if (!virtsnd_pcm_msg_pending_num(vss))
    258		virtsnd_pcm_msg_free(vss);
    259
    260	return 0;
    261}
    262
    263/**
    264 * virtsnd_pcm_prepare() - Prepare the PCM substream.
    265 * @substream: Kernel ALSA substream.
    266 *
    267 * Context: Process context.
    268 * Return: 0 on success, -errno on failure.
    269 */
    270static int virtsnd_pcm_prepare(struct snd_pcm_substream *substream)
    271{
    272	struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream);
    273	struct virtio_device *vdev = vss->snd->vdev;
    274	struct virtio_snd_msg *msg;
    275
    276	if (!vss->suspended) {
    277		if (virtsnd_pcm_msg_pending_num(vss)) {
    278			dev_err(&vdev->dev, "SID %u: invalid I/O queue state\n",
    279				vss->sid);
    280			return -EBADFD;
    281		}
    282
    283		vss->buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
    284		vss->hw_ptr = 0;
    285		vss->msg_last_enqueued = -1;
    286	} else {
    287		struct snd_pcm_runtime *runtime = substream->runtime;
    288		unsigned int buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
    289		unsigned int period_bytes = snd_pcm_lib_period_bytes(substream);
    290		int rc;
    291
    292		rc = virtsnd_pcm_dev_set_params(vss, buffer_bytes, period_bytes,
    293						runtime->channels,
    294						runtime->format, runtime->rate);
    295		if (rc)
    296			return rc;
    297	}
    298
    299	vss->xfer_xrun = false;
    300	vss->suspended = false;
    301	vss->msg_count = 0;
    302
    303	msg = virtsnd_pcm_ctl_msg_alloc(vss, VIRTIO_SND_R_PCM_PREPARE,
    304					GFP_KERNEL);
    305	if (!msg)
    306		return -ENOMEM;
    307
    308	return virtsnd_ctl_msg_send_sync(vss->snd, msg);
    309}
    310
    311/**
    312 * virtsnd_pcm_trigger() - Process command for the PCM substream.
    313 * @substream: Kernel ALSA substream.
    314 * @command: Substream command (SNDRV_PCM_TRIGGER_XXX).
    315 *
    316 * Context: Any context. Takes and releases the VirtIO substream spinlock.
    317 *          May take and release the tx/rx queue spinlock.
    318 * Return: 0 on success, -errno on failure.
    319 */
    320static int virtsnd_pcm_trigger(struct snd_pcm_substream *substream, int command)
    321{
    322	struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream);
    323	struct virtio_snd *snd = vss->snd;
    324	struct virtio_snd_queue *queue;
    325	struct virtio_snd_msg *msg;
    326	unsigned long flags;
    327	int rc;
    328
    329	switch (command) {
    330	case SNDRV_PCM_TRIGGER_START:
    331	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
    332		queue = virtsnd_pcm_queue(vss);
    333
    334		spin_lock_irqsave(&queue->lock, flags);
    335		spin_lock(&vss->lock);
    336		rc = virtsnd_pcm_msg_send(vss);
    337		if (!rc)
    338			vss->xfer_enabled = true;
    339		spin_unlock(&vss->lock);
    340		spin_unlock_irqrestore(&queue->lock, flags);
    341		if (rc)
    342			return rc;
    343
    344		msg = virtsnd_pcm_ctl_msg_alloc(vss, VIRTIO_SND_R_PCM_START,
    345						GFP_KERNEL);
    346		if (!msg) {
    347			spin_lock_irqsave(&vss->lock, flags);
    348			vss->xfer_enabled = false;
    349			spin_unlock_irqrestore(&vss->lock, flags);
    350
    351			return -ENOMEM;
    352		}
    353
    354		return virtsnd_ctl_msg_send_sync(snd, msg);
    355	case SNDRV_PCM_TRIGGER_SUSPEND:
    356		vss->suspended = true;
    357		fallthrough;
    358	case SNDRV_PCM_TRIGGER_STOP:
    359		vss->stopped = true;
    360		fallthrough;
    361	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
    362		spin_lock_irqsave(&vss->lock, flags);
    363		vss->xfer_enabled = false;
    364		spin_unlock_irqrestore(&vss->lock, flags);
    365
    366		msg = virtsnd_pcm_ctl_msg_alloc(vss, VIRTIO_SND_R_PCM_STOP,
    367						GFP_KERNEL);
    368		if (!msg)
    369			return -ENOMEM;
    370
    371		return virtsnd_ctl_msg_send_sync(snd, msg);
    372	default:
    373		return -EINVAL;
    374	}
    375}
    376
    377/**
    378 * virtsnd_pcm_sync_stop() - Synchronous PCM substream stop.
    379 * @substream: Kernel ALSA substream.
    380 *
    381 * The function can be called both from the upper level or from the driver
    382 * itself.
    383 *
    384 * Context: Process context. Takes and releases the VirtIO substream spinlock.
    385 * Return: 0 on success, -errno on failure.
    386 */
    387static int virtsnd_pcm_sync_stop(struct snd_pcm_substream *substream)
    388{
    389	struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream);
    390	struct virtio_snd *snd = vss->snd;
    391	struct virtio_snd_msg *msg;
    392	unsigned int js = msecs_to_jiffies(virtsnd_msg_timeout_ms);
    393	int rc;
    394
    395	cancel_work_sync(&vss->elapsed_period);
    396
    397	if (!vss->stopped)
    398		return 0;
    399
    400	msg = virtsnd_pcm_ctl_msg_alloc(vss, VIRTIO_SND_R_PCM_RELEASE,
    401					GFP_KERNEL);
    402	if (!msg)
    403		return -ENOMEM;
    404
    405	rc = virtsnd_ctl_msg_send_sync(snd, msg);
    406	if (rc)
    407		return rc;
    408
    409	/*
    410	 * The spec states that upon receipt of the RELEASE command "the device
    411	 * MUST complete all pending I/O messages for the specified stream ID".
    412	 * Thus, we consider the absence of I/O messages in the queue as an
    413	 * indication that the substream has been released.
    414	 */
    415	rc = wait_event_interruptible_timeout(vss->msg_empty,
    416					      !virtsnd_pcm_msg_pending_num(vss),
    417					      js);
    418	if (rc <= 0) {
    419		dev_warn(&snd->vdev->dev, "SID %u: failed to flush I/O queue\n",
    420			 vss->sid);
    421
    422		return !rc ? -ETIMEDOUT : rc;
    423	}
    424
    425	vss->stopped = false;
    426
    427	return 0;
    428}
    429
    430/**
    431 * virtsnd_pcm_pointer() - Get the current hardware position for the PCM
    432 *                         substream.
    433 * @substream: Kernel ALSA substream.
    434 *
    435 * Context: Any context. Takes and releases the VirtIO substream spinlock.
    436 * Return: Hardware position in frames inside [0 ... buffer_size) range.
    437 */
    438static snd_pcm_uframes_t
    439virtsnd_pcm_pointer(struct snd_pcm_substream *substream)
    440{
    441	struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream);
    442	snd_pcm_uframes_t hw_ptr = SNDRV_PCM_POS_XRUN;
    443	unsigned long flags;
    444
    445	spin_lock_irqsave(&vss->lock, flags);
    446	if (!vss->xfer_xrun)
    447		hw_ptr = bytes_to_frames(substream->runtime, vss->hw_ptr);
    448	spin_unlock_irqrestore(&vss->lock, flags);
    449
    450	return hw_ptr;
    451}
    452
    453/* PCM substream operators map. */
    454const struct snd_pcm_ops virtsnd_pcm_ops = {
    455	.open = virtsnd_pcm_open,
    456	.close = virtsnd_pcm_close,
    457	.ioctl = snd_pcm_lib_ioctl,
    458	.hw_params = virtsnd_pcm_hw_params,
    459	.hw_free = virtsnd_pcm_hw_free,
    460	.prepare = virtsnd_pcm_prepare,
    461	.trigger = virtsnd_pcm_trigger,
    462	.sync_stop = virtsnd_pcm_sync_stop,
    463	.pointer = virtsnd_pcm_pointer,
    464};