Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (C) 2015 Red Hat, Inc.
0003  * All Rights Reserved.
0004  *
0005  * Authors:
0006  *    Dave Airlie <airlied@redhat.com>
0007  *    Gerd Hoffmann <kraxel@redhat.com>
0008  *
0009  * Permission is hereby granted, free of charge, to any person obtaining a
0010  * copy of this software and associated documentation files (the "Software"),
0011  * to deal in the Software without restriction, including without limitation
0012  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0013  * and/or sell copies of the Software, and to permit persons to whom the
0014  * Software is furnished to do so, subject to the following conditions:
0015  *
0016  * The above copyright notice and this permission notice (including the next
0017  * paragraph) shall be included in all copies or substantial portions of the
0018  * Software.
0019  *
0020  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0021  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0022  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0023  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
0024  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0025  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0026  * OTHER DEALINGS IN THE SOFTWARE.
0027  */
0028 
0029 #include <linux/module.h>
0030 #include <linux/pci.h>
0031 #include <linux/poll.h>
0032 #include <linux/wait.h>
0033 
0034 #include <drm/drm.h>
0035 #include <drm/drm_aperture.h>
0036 #include <drm/drm_atomic_helper.h>
0037 #include <drm/drm_drv.h>
0038 #include <drm/drm_file.h>
0039 
0040 #include "virtgpu_drv.h"
0041 
0042 static const struct drm_driver driver;
0043 
0044 static int virtio_gpu_modeset = -1;
0045 
0046 MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
0047 module_param_named(modeset, virtio_gpu_modeset, int, 0400);
0048 
0049 static int virtio_gpu_pci_quirk(struct drm_device *dev, struct virtio_device *vdev)
0050 {
0051     struct pci_dev *pdev = to_pci_dev(vdev->dev.parent);
0052     const char *pname = dev_name(&pdev->dev);
0053     bool vga = (pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA;
0054     char unique[20];
0055     int ret;
0056 
0057     DRM_INFO("pci: %s detected at %s\n",
0058          vga ? "virtio-vga" : "virtio-gpu-pci",
0059          pname);
0060     if (vga) {
0061         ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, &driver);
0062         if (ret)
0063             return ret;
0064     }
0065 
0066     /*
0067      * Normally the drm_dev_set_unique() call is done by core DRM.
0068      * The following comment covers, why virtio cannot rely on it.
0069      *
0070      * Unlike the other virtual GPU drivers, virtio abstracts the
0071      * underlying bus type by using struct virtio_device.
0072      *
0073      * Hence the dev_is_pci() check, used in core DRM, will fail
0074      * and the unique returned will be the virtio_device "virtio0",
0075      * while a "pci:..." one is required.
0076      *
0077      * A few other ideas were considered:
0078      * - Extend the dev_is_pci() check [in drm_set_busid] to
0079      *   consider virtio.
0080      *   Seems like a bigger hack than what we have already.
0081      *
0082      * - Point drm_device::dev to the parent of the virtio_device
0083      *   Semantic changes:
0084      *   * Using the wrong device for i2c, framebuffer_alloc and
0085      *     prime import.
0086      *   Visual changes:
0087      *   * Helpers such as DRM_DEV_ERROR, dev_info, drm_printer,
0088      *     will print the wrong information.
0089      *
0090      * We could address the latter issues, by introducing
0091      * drm_device::bus_dev, ... which would be used solely for this.
0092      *
0093      * So for the moment keep things as-is, with a bulky comment
0094      * for the next person who feels like removing this
0095      * drm_dev_set_unique() quirk.
0096      */
0097     snprintf(unique, sizeof(unique), "pci:%s", pname);
0098     return drm_dev_set_unique(dev, unique);
0099 }
0100 
0101 static int virtio_gpu_probe(struct virtio_device *vdev)
0102 {
0103     struct drm_device *dev;
0104     int ret;
0105 
0106     if (drm_firmware_drivers_only() && virtio_gpu_modeset == -1)
0107         return -EINVAL;
0108 
0109     if (virtio_gpu_modeset == 0)
0110         return -EINVAL;
0111 
0112     dev = drm_dev_alloc(&driver, &vdev->dev);
0113     if (IS_ERR(dev))
0114         return PTR_ERR(dev);
0115     vdev->priv = dev;
0116 
0117     if (!strcmp(vdev->dev.parent->bus->name, "pci")) {
0118         ret = virtio_gpu_pci_quirk(dev, vdev);
0119         if (ret)
0120             goto err_free;
0121     }
0122 
0123     ret = virtio_gpu_init(dev);
0124     if (ret)
0125         goto err_free;
0126 
0127     ret = drm_dev_register(dev, 0);
0128     if (ret)
0129         goto err_deinit;
0130 
0131     drm_fbdev_generic_setup(vdev->priv, 32);
0132     return 0;
0133 
0134 err_deinit:
0135     virtio_gpu_deinit(dev);
0136 err_free:
0137     drm_dev_put(dev);
0138     return ret;
0139 }
0140 
0141 static void virtio_gpu_remove(struct virtio_device *vdev)
0142 {
0143     struct drm_device *dev = vdev->priv;
0144 
0145     drm_dev_unplug(dev);
0146     drm_atomic_helper_shutdown(dev);
0147     virtio_gpu_deinit(dev);
0148     drm_dev_put(dev);
0149 }
0150 
0151 static void virtio_gpu_config_changed(struct virtio_device *vdev)
0152 {
0153     struct drm_device *dev = vdev->priv;
0154     struct virtio_gpu_device *vgdev = dev->dev_private;
0155 
0156     schedule_work(&vgdev->config_changed_work);
0157 }
0158 
0159 static struct virtio_device_id id_table[] = {
0160     { VIRTIO_ID_GPU, VIRTIO_DEV_ANY_ID },
0161     { 0 },
0162 };
0163 
0164 static unsigned int features[] = {
0165 #ifdef __LITTLE_ENDIAN
0166     /*
0167      * Gallium command stream send by virgl is native endian.
0168      * Because of that we only support little endian guests on
0169      * little endian hosts.
0170      */
0171     VIRTIO_GPU_F_VIRGL,
0172 #endif
0173     VIRTIO_GPU_F_EDID,
0174     VIRTIO_GPU_F_RESOURCE_UUID,
0175     VIRTIO_GPU_F_RESOURCE_BLOB,
0176     VIRTIO_GPU_F_CONTEXT_INIT,
0177 };
0178 static struct virtio_driver virtio_gpu_driver = {
0179     .feature_table = features,
0180     .feature_table_size = ARRAY_SIZE(features),
0181     .driver.name = KBUILD_MODNAME,
0182     .driver.owner = THIS_MODULE,
0183     .id_table = id_table,
0184     .probe = virtio_gpu_probe,
0185     .remove = virtio_gpu_remove,
0186     .config_changed = virtio_gpu_config_changed
0187 };
0188 
0189 module_virtio_driver(virtio_gpu_driver);
0190 
0191 MODULE_DEVICE_TABLE(virtio, id_table);
0192 MODULE_DESCRIPTION("Virtio GPU driver");
0193 MODULE_LICENSE("GPL and additional rights");
0194 MODULE_AUTHOR("Dave Airlie <airlied@redhat.com>");
0195 MODULE_AUTHOR("Gerd Hoffmann <kraxel@redhat.com>");
0196 MODULE_AUTHOR("Alon Levy");
0197 
0198 DEFINE_DRM_GEM_FOPS(virtio_gpu_driver_fops);
0199 
0200 static const struct drm_driver driver = {
0201     .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_RENDER | DRIVER_ATOMIC,
0202     .open = virtio_gpu_driver_open,
0203     .postclose = virtio_gpu_driver_postclose,
0204 
0205     .dumb_create = virtio_gpu_mode_dumb_create,
0206     .dumb_map_offset = virtio_gpu_mode_dumb_mmap,
0207 
0208 #if defined(CONFIG_DEBUG_FS)
0209     .debugfs_init = virtio_gpu_debugfs_init,
0210 #endif
0211     .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
0212     .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
0213     .gem_prime_mmap = drm_gem_prime_mmap,
0214     .gem_prime_import = virtgpu_gem_prime_import,
0215     .gem_prime_import_sg_table = virtgpu_gem_prime_import_sg_table,
0216 
0217     .gem_create_object = virtio_gpu_create_object,
0218     .fops = &virtio_gpu_driver_fops,
0219 
0220     .ioctls = virtio_gpu_ioctls,
0221     .num_ioctls = DRM_VIRTIO_NUM_IOCTLS,
0222 
0223     .name = DRIVER_NAME,
0224     .desc = DRIVER_DESC,
0225     .date = DRIVER_DATE,
0226     .major = DRIVER_MAJOR,
0227     .minor = DRIVER_MINOR,
0228     .patchlevel = DRIVER_PATCHLEVEL,
0229 
0230     .release = virtio_gpu_release,
0231 };