virtio: Backport virtio sound driver.
[AGL/meta-agl.git] / meta-agl-bsp / virtualization-layer / recipes-kernel / linux / linux-yocto / virtio-kmeta / bsp / virtio / virtio-snd / 0009-ALSA-virtio-introduce-device-suspend-resume-support.patch
1 From b173fb2a0eb0067fc665ba48f9b2b8b5f991c078 Mon Sep 17 00:00:00 2001
2 From: Anton Yakovlev <anton.yakovlev@opensynergy.com>
3 Date: Tue, 2 Mar 2021 17:47:09 +0100
4 Subject: [PATCH] ALSA: virtio: introduce device suspend/resume support
5
6 All running PCM substreams are stopped on device suspend and restarted
7 on device resume.
8
9 Signed-off-by: Anton Yakovlev <anton.yakovlev@opensynergy.com>
10 Link: https://lore.kernel.org/r/20210302164709.3142702-10-anton.yakovlev@opensynergy.com
11 Signed-off-by: Takashi Iwai <tiwai@suse.de>
12 Signed-off-by: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
13 ---
14  sound/virtio/virtio_card.c    | 56 +++++++++++++++++++++++++++++++++++
15  sound/virtio/virtio_pcm.h     |  3 ++
16  sound/virtio/virtio_pcm_ops.c | 33 ++++++++++++++++-----
17  3 files changed, 85 insertions(+), 7 deletions(-)
18
19 diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c
20 index 1c03fcc41c3b..ae9128063917 100644
21 --- a/sound/virtio/virtio_card.c
22 +++ b/sound/virtio/virtio_card.c
23 @@ -362,6 +362,58 @@ static void virtsnd_remove(struct virtio_device *vdev)
24         kfree(snd->event_msgs);
25  }
26  
27 +#ifdef CONFIG_PM_SLEEP
28 +/**
29 + * virtsnd_freeze() - Suspend device.
30 + * @vdev: VirtIO parent device.
31 + *
32 + * Context: Any context.
33 + * Return: 0 on success, -errno on failure.
34 + */
35 +static int virtsnd_freeze(struct virtio_device *vdev)
36 +{
37 +       struct virtio_snd *snd = vdev->priv;
38 +       unsigned int i;
39 +
40 +       virtsnd_disable_event_vq(snd);
41 +       virtsnd_ctl_msg_cancel_all(snd);
42 +
43 +       vdev->config->del_vqs(vdev);
44 +       vdev->config->reset(vdev);
45 +
46 +       for (i = 0; i < snd->nsubstreams; ++i)
47 +               cancel_work_sync(&snd->substreams[i].elapsed_period);
48 +
49 +       kfree(snd->event_msgs);
50 +       snd->event_msgs = NULL;
51 +
52 +       return 0;
53 +}
54 +
55 +/**
56 + * virtsnd_restore() - Resume device.
57 + * @vdev: VirtIO parent device.
58 + *
59 + * Context: Any context.
60 + * Return: 0 on success, -errno on failure.
61 + */
62 +static int virtsnd_restore(struct virtio_device *vdev)
63 +{
64 +       struct virtio_snd *snd = vdev->priv;
65 +       int rc;
66 +
67 +       rc = virtsnd_find_vqs(snd);
68 +       if (rc)
69 +               return rc;
70 +
71 +       virtio_device_ready(vdev);
72 +
73 +       virtsnd_enable_event_vq(snd);
74 +
75 +       return 0;
76 +}
77 +#endif /* CONFIG_PM_SLEEP */
78 +
79  static const struct virtio_device_id id_table[] = {
80         { VIRTIO_ID_SOUND, VIRTIO_DEV_ANY_ID },
81         { 0 },
82 @@ -374,6 +426,10 @@ static struct virtio_driver virtsnd_driver = {
83         .validate = virtsnd_validate,
84         .probe = virtsnd_probe,
85         .remove = virtsnd_remove,
86 +#ifdef CONFIG_PM_SLEEP
87 +       .freeze = virtsnd_freeze,
88 +       .restore = virtsnd_restore,
89 +#endif
90  };
91  
92  static int __init init(void)
93 diff --git a/sound/virtio/virtio_pcm.h b/sound/virtio/virtio_pcm.h
94 index 1353fdc9bd69..062eb8e8f2cf 100644
95 --- a/sound/virtio/virtio_pcm.h
96 +++ b/sound/virtio/virtio_pcm.h
97 @@ -31,6 +31,8 @@ struct virtio_pcm_msg;
98   * @xfer_xrun: Data underflow/overflow state (0 - no xrun, 1 - xrun).
99   * @stopped: True if the substream is stopped and must be released on the device
100   *           side.
101 + * @suspended: True if the substream is suspended and must be reconfigured on
102 + *             the device side at resume.
103   * @msgs: Allocated I/O messages.
104   * @nmsgs: Number of allocated I/O messages.
105   * @msg_last_enqueued: Index of the last I/O message added to the virtqueue.
106 @@ -52,6 +54,7 @@ struct virtio_pcm_substream {
107         bool xfer_enabled;
108         bool xfer_xrun;
109         bool stopped;
110 +       bool suspended;
111         struct virtio_pcm_msg **msgs;
112         unsigned int nmsgs;
113         int msg_last_enqueued;
114 diff --git a/sound/virtio/virtio_pcm_ops.c b/sound/virtio/virtio_pcm_ops.c
115 index 0682a2df6c8c..f8bfb87624be 100644
116 --- a/sound/virtio/virtio_pcm_ops.c
117 +++ b/sound/virtio/virtio_pcm_ops.c
118 @@ -115,6 +115,7 @@ static int virtsnd_pcm_open(struct snd_pcm_substream *substream)
119                                       SNDRV_PCM_HW_PARAM_PERIODS);
120  
121         vss->stopped = !!virtsnd_pcm_msg_pending_num(vss);
122 +       vss->suspended = false;
123  
124         /*
125          * If the substream has already been used, then the I/O queue may be in
126 @@ -272,16 +273,31 @@ static int virtsnd_pcm_prepare(struct snd_pcm_substream *substream)
127         struct virtio_device *vdev = vss->snd->vdev;
128         struct virtio_snd_msg *msg;
129  
130 -       if (virtsnd_pcm_msg_pending_num(vss)) {
131 -               dev_err(&vdev->dev, "SID %u: invalid I/O queue state\n",
132 -                       vss->sid);
133 -               return -EBADFD;
134 +       if (!vss->suspended) {
135 +               if (virtsnd_pcm_msg_pending_num(vss)) {
136 +                       dev_err(&vdev->dev, "SID %u: invalid I/O queue state\n",
137 +                               vss->sid);
138 +                       return -EBADFD;
139 +               }
140 +
141 +               vss->buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
142 +               vss->hw_ptr = 0;
143 +               vss->msg_last_enqueued = -1;
144 +       } else {
145 +               struct snd_pcm_runtime *runtime = substream->runtime;
146 +               unsigned int buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
147 +               unsigned int period_bytes = snd_pcm_lib_period_bytes(substream);
148 +               int rc;
149 +
150 +               rc = virtsnd_pcm_dev_set_params(vss, buffer_bytes, period_bytes,
151 +                                               runtime->channels,
152 +                                               runtime->format, runtime->rate);
153 +               if (rc)
154 +                       return rc;
155         }
156  
157 -       vss->buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
158 -       vss->hw_ptr = 0;
159         vss->xfer_xrun = false;
160 -       vss->msg_last_enqueued = -1;
161 +       vss->suspended = false;
162         vss->msg_count = 0;
163  
164         msg = virtsnd_pcm_ctl_msg_alloc(vss, VIRTIO_SND_R_PCM_PREPARE,
165 @@ -336,6 +352,9 @@ static int virtsnd_pcm_trigger(struct snd_pcm_substream *substream, int command)
166                 }
167  
168                 return virtsnd_ctl_msg_send_sync(snd, msg);
169 +       case SNDRV_PCM_TRIGGER_SUSPEND:
170 +               vss->suspended = true;
171 +               fallthrough;
172         case SNDRV_PCM_TRIGGER_STOP:
173                 vss->stopped = true;
174                 fallthrough;