diff options
author | Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com> | 2021-11-22 12:38:06 +0100 |
---|---|---|
committer | Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com> | 2021-12-07 20:47:22 +0100 |
commit | 87b7cce6fb8a0afde96227423b3385d36e6fe0a1 (patch) | |
tree | 052311f8fd70ed9ed4efa0fc2f43bc2d5c452b85 /meta-egvirt/recipes-kernel/kernel-module-virtio-video/files/virtio_video_driver.c | |
parent | 3c2b0cdba520c260a4342d9b968d9efb7892a643 (diff) |
virtualization: Add virtio-video driver as external module.
This driver should conform WIP spec v3 [1] with some updates for spec v4
[2], and, some unspecified features such as VIRTIO_VIDEO_DEVICE_CAMERA.
Imported from internal OpenSynergy's revision:
bcc33b6b9e0156b381a70c54d2df02c57b63d270
Kernel was configured with necessary features for this driver:
enable MEDIA_SUPPORT
disable MEDIA_SUBDRV_AUTOSELECT
enable MEDIA_PLATFORM_SUPPORT
enable VIDEO_VIRTIO
Keep driver as an external module to simplify future updates.
[1]: https://lists.oasis-open.org/archives/virtio-dev/202002/msg00002.html
[2]: https://lists.oasis-open.org/archives/virtio-dev/202006/msg00072.html
Bug-AGL: SPEC-4148
Change-Id: Iea339194b22443f67b3e2ffddca84118357a2f15
Signed-off-by: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
Diffstat (limited to 'meta-egvirt/recipes-kernel/kernel-module-virtio-video/files/virtio_video_driver.c')
-rw-r--r-- | meta-egvirt/recipes-kernel/kernel-module-virtio-video/files/virtio_video_driver.c | 246 |
1 files changed, 246 insertions, 0 deletions
diff --git a/meta-egvirt/recipes-kernel/kernel-module-virtio-video/files/virtio_video_driver.c b/meta-egvirt/recipes-kernel/kernel-module-virtio-video/files/virtio_video_driver.c new file mode 100644 index 00000000..734c5b73 --- /dev/null +++ b/meta-egvirt/recipes-kernel/kernel-module-virtio-video/files/virtio_video_driver.c @@ -0,0 +1,246 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Driver for virtio video device. + * + * Copyright 2020 OpenSynergy GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ +#include <linux/module.h> +#include <linux/version.h> +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) +#include <linux/dma-map-ops.h> +#else +#include <linux/dma-mapping.h> +#endif + +#include "virtio_video.h" + +static unsigned int debug; +module_param(debug, uint, 0644); + +static unsigned int use_dma_mem; +module_param(use_dma_mem, uint, 0644); +MODULE_PARM_DESC(use_dma_mem, "Try to allocate buffers from the DMA zone"); + +static int vid_nr_dec = -1; +module_param(vid_nr_dec, int, 0644); +MODULE_PARM_DESC(vid_nr_dec, "videoN start number, -1 is autodetect"); + +static int vid_nr_enc = -1; +module_param(vid_nr_enc, int, 0644); +MODULE_PARM_DESC(vid_nr_enc, "videoN start number, -1 is autodetect"); + +static int vid_nr_cam = -1; +module_param(vid_nr_cam, int, 0644); +MODULE_PARM_DESC(vid_nr_cam, "videoN start number, -1 is autodetect"); + +static bool mplane_cam = true; +module_param(mplane_cam, bool, 0644); +MODULE_PARM_DESC(mplane_cam, + "1 (default) - multiplanar camera, 0 - single planar camera"); + +static int virtio_video_probe(struct virtio_device *vdev) +{ + int ret; + struct virtio_video_device *vvd; + struct virtqueue *vqs[2]; + struct device *dev = &vdev->dev; + struct device *pdev = dev->parent; + + static const char * const names[] = { "commandq", "eventq" }; + static vq_callback_t *callbacks[] = { + virtio_video_cmd_cb, + virtio_video_event_cb + }; + + if (!virtio_has_feature(vdev, VIRTIO_VIDEO_F_RESOURCE_GUEST_PAGES)) { + dev_err(dev, "device must support guest allocated buffers\n"); + return -ENODEV; + } + + vvd = devm_kzalloc(dev, sizeof(*vvd), GFP_KERNEL); + if (!vvd) + return -ENOMEM; + + vvd->is_m2m_dev = true; + + switch (vdev->id.device) { + case VIRTIO_ID_VIDEO_CAM: + vvd->is_m2m_dev = false; + vvd->vid_dev_nr = vid_nr_cam; + vvd->is_mplane_cam = mplane_cam; + vvd->type = VIRTIO_VIDEO_DEVICE_CAMERA; + break; + case VIRTIO_ID_VIDEO_ENC: + vvd->vid_dev_nr = vid_nr_enc; + vvd->type = VIRTIO_VIDEO_DEVICE_ENCODER; + break; + case VIRTIO_ID_VIDEO_DEC: + default: + vvd->vid_dev_nr = vid_nr_dec; + vvd->type = VIRTIO_VIDEO_DEVICE_DECODER; + break; + } + + vvd->vdev = vdev; + vvd->debug = debug; + vvd->use_dma_mem = use_dma_mem; + vdev->priv = vvd; + + spin_lock_init(&vvd->pending_buf_list_lock); + spin_lock_init(&vvd->resource_idr_lock); + idr_init(&vvd->resource_idr); + spin_lock_init(&vvd->stream_idr_lock); + idr_init(&vvd->stream_idr); + + init_waitqueue_head(&vvd->wq); + + if (virtio_has_feature(vdev, VIRTIO_VIDEO_F_RESOURCE_NON_CONTIG)) + vvd->supp_non_contig = true; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,9,0) + vvd->has_iommu = !virtio_has_dma_quirk(vdev); +#else + vvd->has_iommu = !virtio_has_iommu_quirk(vdev); +#endif + + if (!dev->dma_ops) + set_dma_ops(dev, pdev->dma_ops); + + /* + * Set it to coherent_dma_mask by default if the architecture + * code has not set it. + */ + if (!dev->dma_mask) + dev->dma_mask = &dev->coherent_dma_mask; + + dma_set_mask(dev, *pdev->dma_mask); + + dev_set_name(dev, "%s.%i", DRIVER_NAME, vdev->index); + ret = v4l2_device_register(dev, &vvd->v4l2_dev); + if (ret) + goto err_v4l2_reg; + + spin_lock_init(&vvd->commandq.qlock); + init_waitqueue_head(&vvd->commandq.reclaim_queue); + + INIT_WORK(&vvd->eventq.work, virtio_video_process_events); + + INIT_LIST_HEAD(&vvd->pending_vbuf_list); + + ret = virtio_find_vqs(vdev, 2, vqs, callbacks, names, NULL); + if (ret) { + v4l2_err(&vvd->v4l2_dev, "failed to find virt queues\n"); + goto err_vqs; + } + + vvd->commandq.vq = vqs[0]; + vvd->eventq.vq = vqs[1]; + + ret = virtio_video_alloc_vbufs(vvd); + if (ret) { + v4l2_err(&vvd->v4l2_dev, "failed to alloc vbufs\n"); + goto err_vbufs; + } + + virtio_cread(vdev, struct virtio_video_config, max_caps_length, + &vvd->max_caps_len); + if (!vvd->max_caps_len) { + v4l2_err(&vvd->v4l2_dev, "max_caps_len is zero\n"); + ret = -EINVAL; + goto err_config; + } + + virtio_cread(vdev, struct virtio_video_config, max_resp_length, + &vvd->max_resp_len); + if (!vvd->max_resp_len) { + v4l2_err(&vvd->v4l2_dev, "max_resp_len is zero\n"); + ret = -EINVAL; + goto err_config; + } + + ret = virtio_video_alloc_events(vvd); + if (ret) + goto err_events; + + virtio_device_ready(vdev); + vvd->commandq.ready = true; + vvd->eventq.ready = true; + + ret = virtio_video_device_init(vvd); + if (ret) { + v4l2_err(&vvd->v4l2_dev, + "failed to init virtio video\n"); + goto err_init; + } + + return 0; + +err_init: +err_events: +err_config: + virtio_video_free_vbufs(vvd); +err_vbufs: + vdev->config->del_vqs(vdev); +err_vqs: + v4l2_device_unregister(&vvd->v4l2_dev); +err_v4l2_reg: + devm_kfree(&vdev->dev, vvd); + + return ret; +} + +static void virtio_video_remove(struct virtio_device *vdev) +{ + struct virtio_video_device *vvd = vdev->priv; + + virtio_video_device_deinit(vvd); + virtio_video_free_vbufs(vvd); + vdev->config->del_vqs(vdev); + v4l2_device_unregister(&vvd->v4l2_dev); + devm_kfree(&vdev->dev, vvd); +} + +static struct virtio_device_id id_table[] = { + { VIRTIO_ID_VIDEO_DEC, VIRTIO_DEV_ANY_ID }, + { VIRTIO_ID_VIDEO_ENC, VIRTIO_DEV_ANY_ID }, + { VIRTIO_ID_VIDEO_CAM, VIRTIO_DEV_ANY_ID }, + { 0 }, +}; + +static unsigned int features[] = { + VIRTIO_VIDEO_F_RESOURCE_GUEST_PAGES, + VIRTIO_VIDEO_F_RESOURCE_NON_CONTIG, +}; + +static struct virtio_driver virtio_video_driver = { + .feature_table = features, + .feature_table_size = ARRAY_SIZE(features), + .driver.name = DRIVER_NAME, + .driver.owner = THIS_MODULE, + .id_table = id_table, + .probe = virtio_video_probe, + .remove = virtio_video_remove, +}; + +module_virtio_driver(virtio_video_driver); + +MODULE_DEVICE_TABLE(virtio, id_table); +MODULE_DESCRIPTION("virtio video driver"); +MODULE_AUTHOR("Dmitry Sepp <dmitry.sepp@opensynergy.com>"); +MODULE_AUTHOR("Kiran Pawar <kiran.pawar@opensynergy.com>"); +MODULE_AUTHOR("Nikolay Martyanov <nikolay.martyanov@opensynergy.com>"); +MODULE_AUTHOR("Samiullah Khawaja <samiullah.khawaja@opensynergy.com>"); +MODULE_VERSION(DRIVER_VERSION); +MODULE_LICENSE("GPL"); |