| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- .. SPDX-License-Identifier: GPL-2.0
- .. _writing_virtio_drivers:
- ======================
- Writing Virtio Drivers
- ======================
- Introduction
- ============
- This document serves as a basic guideline for driver programmers that
- need to hack a new virtio driver or understand the essentials of the
- existing ones. See :ref:`Virtio on Linux <virtio>` for a general
- overview of virtio.
- Driver boilerplate
- ==================
- As a bare minimum, a virtio driver needs to register in the virtio bus
- and configure the virtqueues for the device according to its spec, the
- configuration of the virtqueues in the driver side must match the
- virtqueue definitions in the device. A basic driver skeleton could look
- like this::
- #include <linux/virtio.h>
- #include <linux/virtio_ids.h>
- #include <linux/virtio_config.h>
- #include <linux/module.h>
- /* device private data (one per device) */
- struct virtio_dummy_dev {
- struct virtqueue *vq;
- };
- static void virtio_dummy_recv_cb(struct virtqueue *vq)
- {
- struct virtio_dummy_dev *dev = vq->vdev->priv;
- char *buf;
- unsigned int len;
- while ((buf = virtqueue_get_buf(dev->vq, &len)) != NULL) {
- /* process the received data */
- }
- }
- static int virtio_dummy_probe(struct virtio_device *vdev)
- {
- struct virtio_dummy_dev *dev = NULL;
- /* initialize device data */
- dev = kzalloc(sizeof(struct virtio_dummy_dev), GFP_KERNEL);
- if (!dev)
- return -ENOMEM;
- /* the device has a single virtqueue */
- dev->vq = virtio_find_single_vq(vdev, virtio_dummy_recv_cb, "input");
- if (IS_ERR(dev->vq)) {
- kfree(dev);
- return PTR_ERR(dev->vq);
- }
- vdev->priv = dev;
- /* from this point on, the device can notify and get callbacks */
- virtio_device_ready(vdev);
- return 0;
- }
- static void virtio_dummy_remove(struct virtio_device *vdev)
- {
- struct virtio_dummy_dev *dev = vdev->priv;
- /*
- * disable vq interrupts: equivalent to
- * vdev->config->reset(vdev)
- */
- virtio_reset_device(vdev);
- /* detach unused buffers */
- while ((buf = virtqueue_detach_unused_buf(dev->vq)) != NULL) {
- kfree(buf);
- }
- /* remove virtqueues */
- vdev->config->del_vqs(vdev);
- kfree(dev);
- }
- static const struct virtio_device_id id_table[] = {
- { VIRTIO_ID_DUMMY, VIRTIO_DEV_ANY_ID },
- { 0 },
- };
- static struct virtio_driver virtio_dummy_driver = {
- .driver.name = KBUILD_MODNAME,
- .id_table = id_table,
- .probe = virtio_dummy_probe,
- .remove = virtio_dummy_remove,
- };
- module_virtio_driver(virtio_dummy_driver);
- MODULE_DEVICE_TABLE(virtio, id_table);
- MODULE_DESCRIPTION("Dummy virtio driver");
- MODULE_LICENSE("GPL");
- The device id ``VIRTIO_ID_DUMMY`` here is a placeholder, virtio drivers
- should be added only for devices that are defined in the spec, see
- include/uapi/linux/virtio_ids.h. Device ids need to be at least reserved
- in the virtio spec before being added to that file.
- If your driver doesn't have to do anything special in its ``init`` and
- ``exit`` methods, you can use the module_virtio_driver() helper to
- reduce the amount of boilerplate code.
- The ``probe`` method does the minimum driver setup in this case
- (memory allocation for the device data) and initializes the
- virtqueue. virtio_device_ready() is used to enable the virtqueue and to
- notify the device that the driver is ready to manage the device
- ("DRIVER_OK"). The virtqueues are anyway enabled automatically by the
- core after ``probe`` returns.
- .. kernel-doc:: include/linux/virtio_config.h
- :identifiers: virtio_device_ready
- In any case, the virtqueues need to be enabled before adding buffers to
- them.
- Sending and receiving data
- ==========================
- The virtio_dummy_recv_cb() callback in the code above will be triggered
- when the device notifies the driver after it finishes processing a
- descriptor or descriptor chain, either for reading or writing. However,
- that's only the second half of the virtio device-driver communication
- process, as the communication is always started by the driver regardless
- of the direction of the data transfer.
- To configure a buffer transfer from the driver to the device, first you
- have to add the buffers -- packed as `scatterlists` -- to the
- appropriate virtqueue using any of the virtqueue_add_inbuf(),
- virtqueue_add_outbuf() or virtqueue_add_sgs(), depending on whether you
- need to add one input `scatterlist` (for the device to fill in), one
- output `scatterlist` (for the device to consume) or multiple
- `scatterlists`, respectively. Then, once the virtqueue is set up, a call
- to virtqueue_kick() sends a notification that will be serviced by the
- hypervisor that implements the device::
- struct scatterlist sg[1];
- sg_init_one(sg, buffer, BUFLEN);
- virtqueue_add_inbuf(dev->vq, sg, 1, buffer, GFP_ATOMIC);
- virtqueue_kick(dev->vq);
- .. kernel-doc:: drivers/virtio/virtio_ring.c
- :identifiers: virtqueue_add_inbuf
- .. kernel-doc:: drivers/virtio/virtio_ring.c
- :identifiers: virtqueue_add_outbuf
- .. kernel-doc:: drivers/virtio/virtio_ring.c
- :identifiers: virtqueue_add_sgs
- Then, after the device has read or written the buffers prepared by the
- driver and notifies it back, the driver can call virtqueue_get_buf() to
- read the data produced by the device (if the virtqueue was set up with
- input buffers) or simply to reclaim the buffers if they were already
- consumed by the device:
- .. kernel-doc:: drivers/virtio/virtio_ring.c
- :identifiers: virtqueue_get_buf_ctx
- The virtqueue callbacks can be disabled and re-enabled using the
- virtqueue_disable_cb() and the family of virtqueue_enable_cb() functions
- respectively. See drivers/virtio/virtio_ring.c for more details:
- .. kernel-doc:: drivers/virtio/virtio_ring.c
- :identifiers: virtqueue_disable_cb
- .. kernel-doc:: drivers/virtio/virtio_ring.c
- :identifiers: virtqueue_enable_cb
- But note that some spurious callbacks can still be triggered under
- certain scenarios. The way to disable callbacks reliably is to reset the
- device or the virtqueue (virtio_reset_device()).
- References
- ==========
- _`[1]` Virtio Spec v1.2:
- https://docs.oasis-open.org/virtio/virtio/v1.2/virtio-v1.2.html
- Check for later versions of the spec as well.
|