1dc5698e8SDave Airlie /*
2dc5698e8SDave Airlie * Copyright (C) 2015 Red Hat, Inc.
3dc5698e8SDave Airlie * All Rights Reserved.
4dc5698e8SDave Airlie *
5dc5698e8SDave Airlie * Authors:
6dc5698e8SDave Airlie * Dave Airlie <airlied@redhat.com>
7dc5698e8SDave Airlie * Gerd Hoffmann <kraxel@redhat.com>
8dc5698e8SDave Airlie *
9dc5698e8SDave Airlie * Permission is hereby granted, free of charge, to any person obtaining a
10dc5698e8SDave Airlie * copy of this software and associated documentation files (the "Software"),
11dc5698e8SDave Airlie * to deal in the Software without restriction, including without limitation
12dc5698e8SDave Airlie * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13dc5698e8SDave Airlie * and/or sell copies of the Software, and to permit persons to whom the
14dc5698e8SDave Airlie * Software is furnished to do so, subject to the following conditions:
15dc5698e8SDave Airlie *
16dc5698e8SDave Airlie * The above copyright notice and this permission notice (including the next
17dc5698e8SDave Airlie * paragraph) shall be included in all copies or substantial portions of the
18dc5698e8SDave Airlie * Software.
19dc5698e8SDave Airlie *
20dc5698e8SDave Airlie * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21dc5698e8SDave Airlie * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22dc5698e8SDave Airlie * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23dc5698e8SDave Airlie * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
24dc5698e8SDave Airlie * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
25dc5698e8SDave Airlie * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26dc5698e8SDave Airlie * OTHER DEALINGS IN THE SOFTWARE.
27dc5698e8SDave Airlie */
28dc5698e8SDave Airlie
29dc5698e8SDave Airlie #include <linux/module.h>
30dc5698e8SDave Airlie #include <linux/pci.h>
31cd7f5ca3SGurchetan Singh #include <linux/poll.h>
32cd7f5ca3SGurchetan Singh #include <linux/wait.h>
33a3d63977SSam Ravnborg
34ff67a25dSMasahiro Yamada #include <drm/drm.h>
356848c291SThomas Zimmermann #include <drm/drm_aperture.h>
36b1df3a2bSGerd Hoffmann #include <drm/drm_atomic_helper.h>
37a3d63977SSam Ravnborg #include <drm/drm_drv.h>
388ab59da2SThomas Zimmermann #include <drm/drm_fbdev_generic.h>
39a3d63977SSam Ravnborg #include <drm/drm_file.h>
40dc5698e8SDave Airlie
41dc5698e8SDave Airlie #include "virtgpu_drv.h"
42a3d63977SSam Ravnborg
4370a59dd8SDaniel Vetter static const struct drm_driver driver;
44dc5698e8SDave Airlie
45dc5698e8SDave Airlie static int virtio_gpu_modeset = -1;
46dc5698e8SDave Airlie
47dc5698e8SDave Airlie MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
48dc5698e8SDave Airlie module_param_named(modeset, virtio_gpu_modeset, int, 0400);
49dc5698e8SDave Airlie
virtio_gpu_pci_quirk(struct drm_device * dev)50b5c9ed70SDmitry Osipenko static int virtio_gpu_pci_quirk(struct drm_device *dev)
51d516e75cSEzequiel Garcia {
52b5c9ed70SDmitry Osipenko struct pci_dev *pdev = to_pci_dev(dev->dev);
53d516e75cSEzequiel Garcia const char *pname = dev_name(&pdev->dev);
54d516e75cSEzequiel Garcia bool vga = (pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA;
556848c291SThomas Zimmermann int ret;
56d516e75cSEzequiel Garcia
57d516e75cSEzequiel Garcia DRM_INFO("pci: %s detected at %s\n",
58d516e75cSEzequiel Garcia vga ? "virtio-vga" : "virtio-gpu-pci",
59d516e75cSEzequiel Garcia pname);
606848c291SThomas Zimmermann if (vga) {
6197c9bfe3SThomas Zimmermann ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, &driver);
626848c291SThomas Zimmermann if (ret)
636848c291SThomas Zimmermann return ret;
646848c291SThomas Zimmermann }
65d516e75cSEzequiel Garcia
66b5c9ed70SDmitry Osipenko return 0;
67d516e75cSEzequiel Garcia }
68d516e75cSEzequiel Garcia
virtio_gpu_probe(struct virtio_device * vdev)69dc5698e8SDave Airlie static int virtio_gpu_probe(struct virtio_device *vdev)
70dc5698e8SDave Airlie {
71d516e75cSEzequiel Garcia struct drm_device *dev;
7248a77d66SGerd Hoffmann int ret;
7348a77d66SGerd Hoffmann
746a2d2ddfSJavier Martinez Canillas if (drm_firmware_drivers_only() && virtio_gpu_modeset == -1)
75dc5698e8SDave Airlie return -EINVAL;
76dc5698e8SDave Airlie
77dc5698e8SDave Airlie if (virtio_gpu_modeset == 0)
78dc5698e8SDave Airlie return -EINVAL;
79dc5698e8SDave Airlie
80b5c9ed70SDmitry Osipenko /*
81b5c9ed70SDmitry Osipenko * The virtio-gpu device is a virtual device that doesn't have DMA
82b5c9ed70SDmitry Osipenko * ops assigned to it, nor DMA mask set and etc. Its parent device
83b5c9ed70SDmitry Osipenko * is actual GPU device we want to use it for the DRM's device in
84b5c9ed70SDmitry Osipenko * order to benefit from using generic DRM APIs.
85b5c9ed70SDmitry Osipenko */
86b5c9ed70SDmitry Osipenko dev = drm_dev_alloc(&driver, vdev->dev.parent);
87d516e75cSEzequiel Garcia if (IS_ERR(dev))
88d516e75cSEzequiel Garcia return PTR_ERR(dev);
89d516e75cSEzequiel Garcia vdev->priv = dev;
90d516e75cSEzequiel Garcia
91a9d2e8b5SDmitry Osipenko if (dev_is_pci(vdev->dev.parent)) {
92b5c9ed70SDmitry Osipenko ret = virtio_gpu_pci_quirk(dev);
9348a77d66SGerd Hoffmann if (ret)
94d516e75cSEzequiel Garcia goto err_free;
95d516e75cSEzequiel Garcia }
96d516e75cSEzequiel Garcia
97*0b1d4187SSebastian Ott dma_set_max_seg_size(dev->dev, dma_max_mapping_size(dev->dev) ?: UINT_MAX);
98b5c9ed70SDmitry Osipenko ret = virtio_gpu_init(vdev, dev);
99d516e75cSEzequiel Garcia if (ret)
100d516e75cSEzequiel Garcia goto err_free;
101d516e75cSEzequiel Garcia
102d516e75cSEzequiel Garcia ret = drm_dev_register(dev, 0);
103d516e75cSEzequiel Garcia if (ret)
104058acb33SXie Yongji goto err_deinit;
10548a77d66SGerd Hoffmann
10648a77d66SGerd Hoffmann drm_fbdev_generic_setup(vdev->priv, 32);
10748a77d66SGerd Hoffmann return 0;
108d516e75cSEzequiel Garcia
109058acb33SXie Yongji err_deinit:
110058acb33SXie Yongji virtio_gpu_deinit(dev);
111d516e75cSEzequiel Garcia err_free:
112d516e75cSEzequiel Garcia drm_dev_put(dev);
113d516e75cSEzequiel Garcia return ret;
114dc5698e8SDave Airlie }
115dc5698e8SDave Airlie
virtio_gpu_remove(struct virtio_device * vdev)116dc5698e8SDave Airlie static void virtio_gpu_remove(struct virtio_device *vdev)
117dc5698e8SDave Airlie {
118dc5698e8SDave Airlie struct drm_device *dev = vdev->priv;
1199d492b6bSRodrigo Siqueira
120b1df3a2bSGerd Hoffmann drm_dev_unplug(dev);
121b1df3a2bSGerd Hoffmann drm_atomic_helper_shutdown(dev);
122d516e75cSEzequiel Garcia virtio_gpu_deinit(dev);
123c8f95a56SChuhong Yuan drm_dev_put(dev);
124dc5698e8SDave Airlie }
125dc5698e8SDave Airlie
virtio_gpu_config_changed(struct virtio_device * vdev)126dc5698e8SDave Airlie static void virtio_gpu_config_changed(struct virtio_device *vdev)
127dc5698e8SDave Airlie {
128dc5698e8SDave Airlie struct drm_device *dev = vdev->priv;
129dc5698e8SDave Airlie struct virtio_gpu_device *vgdev = dev->dev_private;
130dc5698e8SDave Airlie
131dc5698e8SDave Airlie schedule_work(&vgdev->config_changed_work);
132dc5698e8SDave Airlie }
133dc5698e8SDave Airlie
134dc5698e8SDave Airlie static struct virtio_device_id id_table[] = {
135dc5698e8SDave Airlie { VIRTIO_ID_GPU, VIRTIO_DEV_ANY_ID },
136dc5698e8SDave Airlie { 0 },
137dc5698e8SDave Airlie };
138dc5698e8SDave Airlie
139dc5698e8SDave Airlie static unsigned int features[] = {
14062fb7a5eSGerd Hoffmann #ifdef __LITTLE_ENDIAN
14162fb7a5eSGerd Hoffmann /*
14262fb7a5eSGerd Hoffmann * Gallium command stream send by virgl is native endian.
14362fb7a5eSGerd Hoffmann * Because of that we only support little endian guests on
14462fb7a5eSGerd Hoffmann * little endian hosts.
14562fb7a5eSGerd Hoffmann */
14662fb7a5eSGerd Hoffmann VIRTIO_GPU_F_VIRGL,
14762fb7a5eSGerd Hoffmann #endif
148b4b01b49SGerd Hoffmann VIRTIO_GPU_F_EDID,
149c84adb30SDavid Stevens VIRTIO_GPU_F_RESOURCE_UUID,
1506815cfe6SGerd Hoffmann VIRTIO_GPU_F_RESOURCE_BLOB,
1516198770aSAnthoine Bourgeois VIRTIO_GPU_F_CONTEXT_INIT,
152dc5698e8SDave Airlie };
153dc5698e8SDave Airlie static struct virtio_driver virtio_gpu_driver = {
154dc5698e8SDave Airlie .feature_table = features,
155dc5698e8SDave Airlie .feature_table_size = ARRAY_SIZE(features),
156dc5698e8SDave Airlie .driver.name = KBUILD_MODNAME,
157dc5698e8SDave Airlie .driver.owner = THIS_MODULE,
158dc5698e8SDave Airlie .id_table = id_table,
159dc5698e8SDave Airlie .probe = virtio_gpu_probe,
160dc5698e8SDave Airlie .remove = virtio_gpu_remove,
161dc5698e8SDave Airlie .config_changed = virtio_gpu_config_changed
162dc5698e8SDave Airlie };
163dc5698e8SDave Airlie
164dc5698e8SDave Airlie module_virtio_driver(virtio_gpu_driver);
165dc5698e8SDave Airlie
166dc5698e8SDave Airlie MODULE_DEVICE_TABLE(virtio, id_table);
167dc5698e8SDave Airlie MODULE_DESCRIPTION("Virtio GPU driver");
168dc5698e8SDave Airlie MODULE_LICENSE("GPL and additional rights");
169dc5698e8SDave Airlie MODULE_AUTHOR("Dave Airlie <airlied@redhat.com>");
170dc5698e8SDave Airlie MODULE_AUTHOR("Gerd Hoffmann <kraxel@redhat.com>");
171dc5698e8SDave Airlie MODULE_AUTHOR("Alon Levy");
172dc5698e8SDave Airlie
17342abd004SGurchetan Singh DEFINE_DRM_GEM_FOPS(virtio_gpu_driver_fops);
174dc5698e8SDave Airlie
17570a59dd8SDaniel Vetter static const struct drm_driver driver = {
17672122c69SRob Clark /*
17772122c69SRob Clark * If KMS is disabled DRIVER_MODESET and DRIVER_ATOMIC are masked
17872122c69SRob Clark * out via drm_device::driver_features:
17972122c69SRob Clark */
1807cb8d1abSDmitry Osipenko .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_RENDER | DRIVER_ATOMIC |
18187b3b45cSZack Rusin DRIVER_SYNCOBJ | DRIVER_SYNCOBJ_TIMELINE | DRIVER_CURSOR_HOTSPOT,
18262fb7a5eSGerd Hoffmann .open = virtio_gpu_driver_open,
18362fb7a5eSGerd Hoffmann .postclose = virtio_gpu_driver_postclose,
184dc5698e8SDave Airlie
185dc5698e8SDave Airlie .dumb_create = virtio_gpu_mode_dumb_create,
186dc5698e8SDave Airlie .dumb_map_offset = virtio_gpu_mode_dumb_mmap,
187dc5698e8SDave Airlie
188dc5698e8SDave Airlie #if defined(CONFIG_DEBUG_FS)
189dc5698e8SDave Airlie .debugfs_init = virtio_gpu_debugfs_init,
190dc5698e8SDave Airlie #endif
191c84adb30SDavid Stevens .gem_prime_import = virtgpu_gem_prime_import,
192a0cecc23SDave Airlie .gem_prime_import_sg_table = virtgpu_gem_prime_import_sg_table,
193dc5698e8SDave Airlie
194c66df701SGerd Hoffmann .gem_create_object = virtio_gpu_create_object,
195dc5698e8SDave Airlie .fops = &virtio_gpu_driver_fops,
196dc5698e8SDave Airlie
19762fb7a5eSGerd Hoffmann .ioctls = virtio_gpu_ioctls,
19862fb7a5eSGerd Hoffmann .num_ioctls = DRM_VIRTIO_NUM_IOCTLS,
19962fb7a5eSGerd Hoffmann
200dc5698e8SDave Airlie .name = DRIVER_NAME,
201dc5698e8SDave Airlie .desc = DRIVER_DESC,
202dc5698e8SDave Airlie .date = DRIVER_DATE,
203dc5698e8SDave Airlie .major = DRIVER_MAJOR,
204dc5698e8SDave Airlie .minor = DRIVER_MINOR,
205dc5698e8SDave Airlie .patchlevel = DRIVER_PATCHLEVEL,
206b1df3a2bSGerd Hoffmann
207b1df3a2bSGerd Hoffmann .release = virtio_gpu_release,
208dc5698e8SDave Airlie };
209