/** * struct virtio_snd_msg - Control message. * @sg_request: Scattergather list containing a device request (header). * @sg_response: Scattergather list containing a device response (status). * @list: Pending message list entry. * @notify: Request completed notification. * @ref_count: Reference count used to manage a message lifetime.
*/ struct virtio_snd_msg { struct scatterlist sg_request; struct scatterlist sg_response; struct list_head list; struct completion notify;
refcount_t ref_count;
};
/** * virtsnd_ctl_msg_ref() - Increment reference counter for the message. * @msg: Control message. * * Context: Any context.
*/ void virtsnd_ctl_msg_ref(struct virtio_snd_msg *msg)
{
refcount_inc(&msg->ref_count);
}
/** * virtsnd_ctl_msg_unref() - Decrement reference counter for the message. * @msg: Control message. * * The message will be freed when the ref_count value is 0. * * Context: Any context.
*/ void virtsnd_ctl_msg_unref(struct virtio_snd_msg *msg)
{ if (refcount_dec_and_test(&msg->ref_count))
kfree(msg);
}
/** * virtsnd_ctl_msg_request() - Get a pointer to the request header. * @msg: Control message. * * Context: Any context.
*/ void *virtsnd_ctl_msg_request(struct virtio_snd_msg *msg)
{ return sg_virt(&msg->sg_request);
}
/** * virtsnd_ctl_msg_response() - Get a pointer to the response header. * @msg: Control message. * * Context: Any context.
*/ void *virtsnd_ctl_msg_response(struct virtio_snd_msg *msg)
{ return sg_virt(&msg->sg_response);
}
/** * virtsnd_ctl_msg_alloc() - Allocate and initialize a control message. * @request_size: Size of request header. * @response_size: Size of response header. * @gfp: Kernel flags for memory allocation. * * The message will be automatically freed when the ref_count value is 0. * * Context: Any context. May sleep if @gfp flags permit. * Return: Allocated message on success, NULL on failure.
*/ struct virtio_snd_msg *virtsnd_ctl_msg_alloc(size_t request_size,
size_t response_size, gfp_t gfp)
{ struct virtio_snd_msg *msg;
INIT_LIST_HEAD(&msg->list);
init_completion(&msg->notify); /* This reference is dropped in virtsnd_ctl_msg_complete(). */
refcount_set(&msg->ref_count, 1);
return msg;
}
/** * virtsnd_ctl_msg_send() - Send a control message. * @snd: VirtIO sound device. * @msg: Control message. * @out_sgs: Additional sg-list to attach to the request header (may be NULL). * @in_sgs: Additional sg-list to attach to the response header (may be NULL). * @nowait: Flag indicating whether to wait for completion. * * Context: Any context. Takes and releases the control queue spinlock. * May sleep if @nowait is false. * Return: 0 on success, -errno on failure.
*/ int virtsnd_ctl_msg_send(struct virtio_snd *snd, struct virtio_snd_msg *msg, struct scatterlist *out_sgs, struct scatterlist *in_sgs, bool nowait)
{ struct virtio_device *vdev = snd->vdev; struct virtio_snd_queue *queue = virtsnd_control_queue(snd); unsignedint js = msecs_to_jiffies(virtsnd_msg_timeout_ms); struct virtio_snd_hdr *request = virtsnd_ctl_msg_request(msg); struct virtio_snd_hdr *response = virtsnd_ctl_msg_response(msg); unsignedint nouts = 0; unsignedint nins = 0; struct scatterlist *psgs[4]; bool notify = false; unsignedlong flags; int rc;
virtsnd_ctl_msg_ref(msg);
/* Set the default status in case the message was canceled. */
response->code = cpu_to_le32(VIRTIO_SND_S_IO_ERR);
psgs[nouts++] = &msg->sg_request; if (out_sgs)
psgs[nouts++] = out_sgs;
if (rc) {
dev_err(&vdev->dev, "failed to send control message (0x%08x)\n",
le32_to_cpu(request->code));
/* * Since in this case virtsnd_ctl_msg_complete() will not be * called, it is necessary to decrement the reference count.
*/
virtsnd_ctl_msg_unref(msg);
switch (le32_to_cpu(response->code)) { case VIRTIO_SND_S_OK:
rc = 0; break; case VIRTIO_SND_S_NOT_SUPP:
rc = -EOPNOTSUPP; break; case VIRTIO_SND_S_IO_ERR:
rc = -EIO; break; default:
rc = -EINVAL; break;
}
on_exit:
virtsnd_ctl_msg_unref(msg);
return rc;
}
/** * virtsnd_ctl_msg_complete() - Complete a control message. * @msg: Control message. * * Context: Any context. Expects the control queue spinlock to be held by * caller.
*/ void virtsnd_ctl_msg_complete(struct virtio_snd_msg *msg)
{
list_del(&msg->list);
complete(&msg->notify);
/** * virtsnd_ctl_notify_cb() - Process all completed control messages. * @vqueue: Underlying control virtqueue. * * This callback function is called upon a vring interrupt request from the * device. * * Context: Interrupt context. Takes and releases the control queue spinlock.
*/ void virtsnd_ctl_notify_cb(struct virtqueue *vqueue)
{ struct virtio_snd *snd = vqueue->vdev->priv; struct virtio_snd_queue *queue = virtsnd_control_queue(snd); struct virtio_snd_msg *msg;
u32 length; unsignedlong flags;
spin_lock_irqsave(&queue->lock, flags); do {
virtqueue_disable_cb(vqueue); while ((msg = virtqueue_get_buf(vqueue, &length)))
virtsnd_ctl_msg_complete(msg);
} while (!virtqueue_enable_cb(vqueue));
spin_unlock_irqrestore(&queue->lock, flags);
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.