]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - ubuntu/vbox/vboxvideo/vbox_drv.c
UBUNTU: ubuntu: vbox -- update to 5.2.0-dfsg-2
[mirror_ubuntu-bionic-kernel.git] / ubuntu / vbox / vboxvideo / vbox_drv.c
CommitLineData
056a1eb7 1/* $Id: vbox_drv.c $ */
056a1eb7 2/*
6d209b23
SF
3 * Copyright (C) 2013-2017 Oracle Corporation
4 * This file is based on ast_drv.c
056a1eb7
SF
5 * Copyright 2012 Red Hat Inc.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sub license, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE.
22 *
23 * The above copyright notice and this permission notice (including the
24 * next paragraph) shall be included in all copies or substantial portions
25 * of the Software.
26 *
056a1eb7 27 * Authors: Dave Airlie <airlied@redhat.com>
6d209b23
SF
28 * Michael Thayer <michael.thayer@oracle.com,
29 * Hans de Goede <hdegoede@redhat.com>
056a1eb7
SF
30 */
31#include "vbox_drv.h"
32
056a1eb7
SF
33#include "version-generated.h"
34#include "revision-generated.h"
35
36#include <linux/module.h>
37#include <linux/console.h>
38#include <linux/vt_kern.h>
39
40#include <drm/drmP.h>
41#include <drm/drm_crtc_helper.h>
42
43int vbox_modeset = -1;
44
45MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
46module_param_named(modeset, vbox_modeset, int, 0400);
47
48static struct drm_driver driver;
49
6d209b23
SF
50static const struct pci_device_id pciidlist[] = { { 0x80ee, 0xbeef, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
51 { 0, 0, 0},
056a1eb7 52};
056a1eb7
SF
53MODULE_DEVICE_TABLE(pci, pciidlist);
54
55static int vbox_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
56{
6d209b23 57 return drm_get_pci_dev(pdev, ent, &driver);
056a1eb7
SF
58}
59
056a1eb7
SF
60static void vbox_pci_remove(struct pci_dev *pdev)
61{
6d209b23 62 struct drm_device *dev = pci_get_drvdata(pdev);
056a1eb7 63
6d209b23 64 drm_put_dev(dev);
056a1eb7
SF
65}
66
056a1eb7
SF
67static int vbox_drm_freeze(struct drm_device *dev)
68{
6d209b23
SF
69 drm_kms_helper_poll_disable(dev);
70
71 pci_save_state(dev->pdev);
056a1eb7 72
6d209b23
SF
73 console_lock();
74 vbox_fbdev_set_suspend(dev, 1);
75 console_unlock();
056a1eb7 76
6d209b23 77 return 0;
056a1eb7
SF
78}
79
80static int vbox_drm_thaw(struct drm_device *dev)
81{
6d209b23
SF
82 drm_mode_config_reset(dev);
83 drm_helper_resume_force_mode(dev);
056a1eb7 84
6d209b23
SF
85 console_lock();
86 vbox_fbdev_set_suspend(dev, 0);
87 console_unlock();
056a1eb7 88
6d209b23 89 return 0;
056a1eb7
SF
90}
91
92static int vbox_drm_resume(struct drm_device *dev)
93{
6d209b23
SF
94 int ret;
95
96 if (pci_enable_device(dev->pdev))
97 return -EIO;
056a1eb7 98
6d209b23
SF
99 ret = vbox_drm_thaw(dev);
100 if (ret)
101 return ret;
056a1eb7 102
6d209b23 103 drm_kms_helper_poll_enable(dev);
056a1eb7 104
6d209b23 105 return 0;
056a1eb7
SF
106}
107
108static int vbox_pm_suspend(struct device *dev)
109{
6d209b23
SF
110 struct pci_dev *pdev = to_pci_dev(dev);
111 struct drm_device *ddev = pci_get_drvdata(pdev);
112 int error;
056a1eb7 113
6d209b23
SF
114 error = vbox_drm_freeze(ddev);
115 if (error)
116 return error;
056a1eb7 117
6d209b23
SF
118 pci_disable_device(pdev);
119 pci_set_power_state(pdev, PCI_D3hot);
120
121 return 0;
056a1eb7
SF
122}
123
124static int vbox_pm_resume(struct device *dev)
125{
6d209b23
SF
126 struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
127
128 return vbox_drm_resume(ddev);
056a1eb7
SF
129}
130
131static int vbox_pm_freeze(struct device *dev)
132{
6d209b23
SF
133 struct pci_dev *pdev = to_pci_dev(dev);
134 struct drm_device *ddev = pci_get_drvdata(pdev);
056a1eb7 135
6d209b23
SF
136 if (!ddev || !ddev->dev_private)
137 return -ENODEV;
056a1eb7 138
6d209b23 139 return vbox_drm_freeze(ddev);
056a1eb7
SF
140}
141
142static int vbox_pm_thaw(struct device *dev)
143{
6d209b23
SF
144 struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
145
146 return vbox_drm_thaw(ddev);
056a1eb7
SF
147}
148
149static int vbox_pm_poweroff(struct device *dev)
150{
6d209b23 151 struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
056a1eb7 152
6d209b23 153 return vbox_drm_freeze(ddev);
056a1eb7
SF
154}
155
156static const struct dev_pm_ops vbox_pm_ops = {
6d209b23
SF
157 .suspend = vbox_pm_suspend,
158 .resume = vbox_pm_resume,
159 .freeze = vbox_pm_freeze,
160 .thaw = vbox_pm_thaw,
161 .poweroff = vbox_pm_poweroff,
162 .restore = vbox_pm_resume,
056a1eb7
SF
163};
164
6d209b23
SF
165static struct pci_driver vbox_pci_driver = {
166 .name = DRIVER_NAME,
167 .id_table = pciidlist,
168 .probe = vbox_pci_probe,
169 .remove = vbox_pci_remove,
170 .driver.pm = &vbox_pm_ops,
056a1eb7
SF
171};
172
173#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0) && !defined(RHEL_74)
174/* This works around a bug in X servers prior to 1.18.4, which sometimes
175 * submit more dirty rectangles than the kernel is willing to handle and
176 * then disable dirty rectangle handling altogether when they see the
177 * EINVAL error. I do not want the code to hang around forever, which is
178 * why I am limiting it to certain kernel versions. We can increase the
179 * limit if some distributions uses old X servers with new kernels. */
6d209b23 180long vbox_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
056a1eb7 181{
6d209b23
SF
182 long rc = drm_ioctl(filp, cmd, arg);
183
184 if (cmd == DRM_IOCTL_MODE_DIRTYFB && rc == -EINVAL)
185 return -EOVERFLOW;
186
187 return rc;
056a1eb7
SF
188}
189#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0) && !RHEL_74 */
190
6d209b23
SF
191static const struct file_operations vbox_fops = {
192 .owner = THIS_MODULE,
193 .open = drm_open,
194 .release = drm_release,
056a1eb7 195#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0) && !defined(RHEL_74)
6d209b23 196 .unlocked_ioctl = vbox_ioctl,
056a1eb7 197#else
6d209b23 198 .unlocked_ioctl = drm_ioctl,
056a1eb7 199#endif
6d209b23
SF
200 .mmap = vbox_mmap,
201 .poll = drm_poll,
056a1eb7 202#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0) && !defined(RHEL_73)
6d209b23 203 .fasync = drm_fasync,
056a1eb7
SF
204#endif
205#ifdef CONFIG_COMPAT
6d209b23 206 .compat_ioctl = drm_compat_ioctl,
056a1eb7 207#endif
6d209b23 208 .read = drm_read,
056a1eb7
SF
209};
210
211static int vbox_master_set(struct drm_device *dev,
6d209b23 212 struct drm_file *file_priv, bool from_open)
056a1eb7 213{
6d209b23
SF
214 struct vbox_private *vbox = dev->dev_private;
215
216 /*
217 * We do not yet know whether the new owner can handle hotplug, so we
218 * do not advertise dynamic modes on the first query and send a
219 * tentative hotplug notification after that to see if they query again.
220 */
221 vbox->initial_mode_queried = false;
222
223 mutex_lock(&vbox->hw_mutex);
224 /*
225 * Disable VBVA when someone releases master in case the next person
226 * tries tries to do VESA.
227 */
228 /** @todo work out if anyone is likely to and whether it will work. */
229 /*
230 * Update: we also disable it because if the new master does not do
231 * dirty rectangle reporting (e.g. old versions of Plymouth) then at
232 * least the first screen will still be updated. We enable it as soon
233 * as we receive a dirty rectangle report.
234 */
235 vbox_disable_accel(vbox);
236 mutex_unlock(&vbox->hw_mutex);
237
238 return 0;
056a1eb7
SF
239}
240
241#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0) && !defined(RHEL_74)
242static void vbox_master_drop(struct drm_device *dev,
6d209b23 243 struct drm_file *file_priv, bool from_release)
056a1eb7 244#else
6d209b23 245static void vbox_master_drop(struct drm_device *dev, struct drm_file *file_priv)
056a1eb7
SF
246#endif
247{
6d209b23
SF
248 struct vbox_private *vbox = dev->dev_private;
249
250 /* See vbox_master_set() */
251 vbox->initial_mode_queried = false;
252
253 mutex_lock(&vbox->hw_mutex);
254 vbox_disable_accel(vbox);
255 mutex_unlock(&vbox->hw_mutex);
056a1eb7
SF
256}
257
6d209b23
SF
258static struct drm_driver driver = {
259 .driver_features =
260 DRIVER_MODESET | DRIVER_GEM | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
261 DRIVER_PRIME,
262 .dev_priv_size = 0,
263
264 .load = vbox_driver_load,
265 .unload = vbox_driver_unload,
266 .lastclose = vbox_driver_lastclose,
267 .master_set = vbox_master_set,
268 .master_drop = vbox_master_drop,
056a1eb7 269#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0) || defined(RHEL_73)
6d209b23
SF
270# if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
271 .set_busid = drm_pci_set_busid,
272# endif
056a1eb7
SF
273#endif
274
6d209b23
SF
275 .fops = &vbox_fops,
276 .irq_handler = vbox_irq_handler,
277 .name = DRIVER_NAME,
278 .desc = DRIVER_DESC,
279 .date = DRIVER_DATE,
280 .major = DRIVER_MAJOR,
281 .minor = DRIVER_MINOR,
282 .patchlevel = DRIVER_PATCHLEVEL,
283
284 .gem_free_object = vbox_gem_free_object,
285 .dumb_create = vbox_dumb_create,
286 .dumb_map_offset = vbox_dumb_mmap_offset,
056a1eb7 287#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0) && !defined(RHEL_73)
6d209b23 288 .dumb_destroy = vbox_dumb_destroy,
056a1eb7 289#else
6d209b23 290 .dumb_destroy = drm_gem_dumb_destroy,
056a1eb7 291#endif
6d209b23
SF
292 .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
293 .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
294 .gem_prime_export = drm_gem_prime_export,
295 .gem_prime_import = drm_gem_prime_import,
296 .gem_prime_pin = vbox_gem_prime_pin,
297 .gem_prime_unpin = vbox_gem_prime_unpin,
298 .gem_prime_get_sg_table = vbox_gem_prime_get_sg_table,
299 .gem_prime_import_sg_table = vbox_gem_prime_import_sg_table,
300 .gem_prime_vmap = vbox_gem_prime_vmap,
301 .gem_prime_vunmap = vbox_gem_prime_vunmap,
302 .gem_prime_mmap = vbox_gem_prime_mmap,
056a1eb7
SF
303};
304
305static int __init vbox_init(void)
306{
6d209b23
SF
307#ifdef CONFIG_VGA_CONSOLE || LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)
308 if (vgacon_text_force() && vbox_modeset == -1)
309 return -EINVAL;
056a1eb7
SF
310#endif
311
6d209b23
SF
312 if (vbox_modeset == 0)
313 return -EINVAL;
056a1eb7 314
6d209b23 315 return pci_register_driver(&vbox_pci_driver);
056a1eb7 316}
6d209b23 317
056a1eb7
SF
318static void __exit vbox_exit(void)
319{
6d209b23 320 pci_unregister_driver(&vbox_pci_driver);
056a1eb7
SF
321}
322
323module_init(vbox_init);
324module_exit(vbox_exit);
325
326MODULE_AUTHOR(DRIVER_AUTHOR);
327MODULE_DESCRIPTION(DRIVER_DESC);
328MODULE_LICENSE("GPL and additional rights");
329#ifdef MODULE_VERSION
6d209b23 330MODULE_VERSION(VBOX_VERSION_STRING " r" __stringify(VBOX_SVN_REV));
056a1eb7 331#endif