0001
0002
0003
0004
0005
0006 #include <sound/pcm_params.h>
0007
0008 #include "virtio_card.h"
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018 struct virtio_pcm_msg {
0019 struct virtio_pcm_substream *substream;
0020 struct virtio_snd_pcm_xfer xfer;
0021 struct virtio_snd_pcm_status status;
0022 size_t length;
0023 struct scatterlist sgs[];
0024 };
0025
0026
0027
0028
0029
0030
0031
0032
0033 enum pcm_msg_sg_index {
0034 PCM_MSG_SG_XFER = 0,
0035 PCM_MSG_SG_STATUS,
0036 PCM_MSG_SG_DATA
0037 };
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048 static int virtsnd_pcm_sg_num(u8 *data, unsigned int length)
0049 {
0050 phys_addr_t sg_address;
0051 unsigned int sg_length;
0052 int num = 0;
0053
0054 while (length) {
0055 struct page *pg = vmalloc_to_page(data);
0056 phys_addr_t pg_address = page_to_phys(pg);
0057 size_t pg_length;
0058
0059 pg_length = PAGE_SIZE - offset_in_page(data);
0060 if (pg_length > length)
0061 pg_length = length;
0062
0063 if (!num || sg_address + sg_length != pg_address) {
0064 sg_address = pg_address;
0065 sg_length = pg_length;
0066 num++;
0067 } else {
0068 sg_length += pg_length;
0069 }
0070
0071 data += pg_length;
0072 length -= pg_length;
0073 }
0074
0075 return num;
0076 }
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090 static void virtsnd_pcm_sg_from(struct scatterlist *sgs, int nsgs, u8 *data,
0091 unsigned int length)
0092 {
0093 int idx = -1;
0094
0095 while (length) {
0096 struct page *pg = vmalloc_to_page(data);
0097 size_t pg_length;
0098
0099 pg_length = PAGE_SIZE - offset_in_page(data);
0100 if (pg_length > length)
0101 pg_length = length;
0102
0103 if (idx == -1 ||
0104 sg_phys(&sgs[idx]) + sgs[idx].length != page_to_phys(pg)) {
0105 if (idx + 1 == nsgs)
0106 break;
0107 sg_set_page(&sgs[++idx], pg, pg_length,
0108 offset_in_page(data));
0109 } else {
0110 sgs[idx].length += pg_length;
0111 }
0112
0113 data += pg_length;
0114 length -= pg_length;
0115 }
0116
0117 sg_mark_end(&sgs[idx]);
0118 }
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132 int virtsnd_pcm_msg_alloc(struct virtio_pcm_substream *vss,
0133 unsigned int periods, unsigned int period_bytes)
0134 {
0135 struct snd_pcm_runtime *runtime = vss->substream->runtime;
0136 unsigned int i;
0137
0138 vss->msgs = kcalloc(periods, sizeof(*vss->msgs), GFP_KERNEL);
0139 if (!vss->msgs)
0140 return -ENOMEM;
0141
0142 vss->nmsgs = periods;
0143
0144 for (i = 0; i < periods; ++i) {
0145 u8 *data = runtime->dma_area + period_bytes * i;
0146 int sg_num = virtsnd_pcm_sg_num(data, period_bytes);
0147 struct virtio_pcm_msg *msg;
0148
0149 msg = kzalloc(struct_size(msg, sgs, sg_num + 2), GFP_KERNEL);
0150 if (!msg)
0151 return -ENOMEM;
0152
0153 msg->substream = vss;
0154 sg_init_one(&msg->sgs[PCM_MSG_SG_XFER], &msg->xfer,
0155 sizeof(msg->xfer));
0156 sg_init_one(&msg->sgs[PCM_MSG_SG_STATUS], &msg->status,
0157 sizeof(msg->status));
0158 msg->length = period_bytes;
0159 virtsnd_pcm_sg_from(&msg->sgs[PCM_MSG_SG_DATA], sg_num, data,
0160 period_bytes);
0161
0162 vss->msgs[i] = msg;
0163 }
0164
0165 return 0;
0166 }
0167
0168
0169
0170
0171
0172
0173
0174 void virtsnd_pcm_msg_free(struct virtio_pcm_substream *vss)
0175 {
0176 unsigned int i;
0177
0178 for (i = 0; vss->msgs && i < vss->nmsgs; ++i)
0179 kfree(vss->msgs[i]);
0180 kfree(vss->msgs);
0181
0182 vss->msgs = NULL;
0183 vss->nmsgs = 0;
0184 }
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201 int virtsnd_pcm_msg_send(struct virtio_pcm_substream *vss)
0202 {
0203 struct snd_pcm_runtime *runtime = vss->substream->runtime;
0204 struct virtio_snd *snd = vss->snd;
0205 struct virtio_device *vdev = snd->vdev;
0206 struct virtqueue *vqueue = virtsnd_pcm_queue(vss)->vqueue;
0207 int i;
0208 int n;
0209 bool notify = false;
0210
0211 i = (vss->msg_last_enqueued + 1) % runtime->periods;
0212 n = runtime->periods - vss->msg_count;
0213
0214 for (; n; --n, i = (i + 1) % runtime->periods) {
0215 struct virtio_pcm_msg *msg = vss->msgs[i];
0216 struct scatterlist *psgs[] = {
0217 &msg->sgs[PCM_MSG_SG_XFER],
0218 &msg->sgs[PCM_MSG_SG_DATA],
0219 &msg->sgs[PCM_MSG_SG_STATUS]
0220 };
0221 int rc;
0222
0223 msg->xfer.stream_id = cpu_to_le32(vss->sid);
0224 memset(&msg->status, 0, sizeof(msg->status));
0225
0226 if (vss->direction == SNDRV_PCM_STREAM_PLAYBACK)
0227 rc = virtqueue_add_sgs(vqueue, psgs, 2, 1, msg,
0228 GFP_ATOMIC);
0229 else
0230 rc = virtqueue_add_sgs(vqueue, psgs, 1, 2, msg,
0231 GFP_ATOMIC);
0232
0233 if (rc) {
0234 dev_err(&vdev->dev,
0235 "SID %u: failed to send I/O message\n",
0236 vss->sid);
0237 return rc;
0238 }
0239
0240 vss->msg_last_enqueued = i;
0241 vss->msg_count++;
0242 }
0243
0244 if (!(vss->features & (1U << VIRTIO_SND_PCM_F_MSG_POLLING)))
0245 notify = virtqueue_kick_prepare(vqueue);
0246
0247 if (notify)
0248 virtqueue_notify(vqueue);
0249
0250 return 0;
0251 }
0252
0253
0254
0255
0256
0257
0258
0259
0260 unsigned int virtsnd_pcm_msg_pending_num(struct virtio_pcm_substream *vss)
0261 {
0262 unsigned int num;
0263 unsigned long flags;
0264
0265 spin_lock_irqsave(&vss->lock, flags);
0266 num = vss->msg_count;
0267 spin_unlock_irqrestore(&vss->lock, flags);
0268
0269 return num;
0270 }
0271
0272
0273
0274
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288 static void virtsnd_pcm_msg_complete(struct virtio_pcm_msg *msg,
0289 size_t written_bytes)
0290 {
0291 struct virtio_pcm_substream *vss = msg->substream;
0292
0293
0294
0295
0296
0297
0298 spin_lock(&vss->lock);
0299
0300
0301
0302
0303 if (vss->direction == SNDRV_PCM_STREAM_PLAYBACK ||
0304 written_bytes <= sizeof(msg->status))
0305 vss->hw_ptr += msg->length;
0306 else
0307 vss->hw_ptr += written_bytes - sizeof(msg->status);
0308
0309 if (vss->hw_ptr >= vss->buffer_bytes)
0310 vss->hw_ptr -= vss->buffer_bytes;
0311
0312 vss->xfer_xrun = false;
0313 vss->msg_count--;
0314
0315 if (vss->xfer_enabled) {
0316 struct snd_pcm_runtime *runtime = vss->substream->runtime;
0317
0318 runtime->delay =
0319 bytes_to_frames(runtime,
0320 le32_to_cpu(msg->status.latency_bytes));
0321
0322 schedule_work(&vss->elapsed_period);
0323
0324 virtsnd_pcm_msg_send(vss);
0325 } else if (!vss->msg_count) {
0326 wake_up_all(&vss->msg_empty);
0327 }
0328 spin_unlock(&vss->lock);
0329 }
0330
0331
0332
0333
0334
0335
0336
0337 static inline void virtsnd_pcm_notify_cb(struct virtio_snd_queue *queue)
0338 {
0339 struct virtio_pcm_msg *msg;
0340 u32 written_bytes;
0341 unsigned long flags;
0342
0343 spin_lock_irqsave(&queue->lock, flags);
0344 do {
0345 virtqueue_disable_cb(queue->vqueue);
0346 while ((msg = virtqueue_get_buf(queue->vqueue, &written_bytes)))
0347 virtsnd_pcm_msg_complete(msg, written_bytes);
0348 if (unlikely(virtqueue_is_broken(queue->vqueue)))
0349 break;
0350 } while (!virtqueue_enable_cb(queue->vqueue));
0351 spin_unlock_irqrestore(&queue->lock, flags);
0352 }
0353
0354
0355
0356
0357
0358
0359
0360 void virtsnd_pcm_tx_notify_cb(struct virtqueue *vqueue)
0361 {
0362 struct virtio_snd *snd = vqueue->vdev->priv;
0363
0364 virtsnd_pcm_notify_cb(virtsnd_tx_queue(snd));
0365 }
0366
0367
0368
0369
0370
0371
0372
0373 void virtsnd_pcm_rx_notify_cb(struct virtqueue *vqueue)
0374 {
0375 struct virtio_snd *snd = vqueue->vdev->priv;
0376
0377 virtsnd_pcm_notify_cb(virtsnd_rx_queue(snd));
0378 }
0379
0380
0381
0382
0383
0384
0385
0386
0387
0388
0389
0390 struct virtio_snd_msg *
0391 virtsnd_pcm_ctl_msg_alloc(struct virtio_pcm_substream *vss,
0392 unsigned int command, gfp_t gfp)
0393 {
0394 size_t request_size = sizeof(struct virtio_snd_pcm_hdr);
0395 size_t response_size = sizeof(struct virtio_snd_hdr);
0396 struct virtio_snd_msg *msg;
0397
0398 switch (command) {
0399 case VIRTIO_SND_R_PCM_SET_PARAMS:
0400 request_size = sizeof(struct virtio_snd_pcm_set_params);
0401 break;
0402 }
0403
0404 msg = virtsnd_ctl_msg_alloc(request_size, response_size, gfp);
0405 if (msg) {
0406 struct virtio_snd_pcm_hdr *hdr = virtsnd_ctl_msg_request(msg);
0407
0408 hdr->hdr.code = cpu_to_le32(command);
0409 hdr->stream_id = cpu_to_le32(vss->sid);
0410 }
0411
0412 return msg;
0413 }