VirtualBox

source: vbox/trunk/src/VBox/Additions/linux/drm/vbox_drv.c@ 102874

Last change on this file since 102874 was 102874, checked in by vboxsync, 4 months ago

Linux Host and Guest kernel modules: Fix build for older Fedora kernels.

This commit covers build errors for Fedora 34-38 kernels. In short,
we exclude Fedora kernels (identified as RHEL XX.99) from fixes intended
for RHEL kernels.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.5 KB
Line 
1/* $Id: vbox_drv.c 102874 2024-01-15 12:08:04Z vboxsync $ */
2/** @file
3 * VirtualBox Additions Linux kernel video driver
4 */
5
6/*
7 * Copyright (C) 2013-2023 Oracle and/or its affiliates.
8 * This file is based on ast_drv.c
9 * Copyright 2012 Red Hat Inc.
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the
13 * "Software"), to deal in the Software without restriction, including
14 * without limitation the rights to use, copy, modify, merge, publish,
15 * distribute, sub license, and/or sell copies of the Software, and to
16 * permit persons to whom the Software is furnished to do so, subject to
17 * the following conditions:
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
22 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
23 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
25 * USE OR OTHER DEALINGS IN THE SOFTWARE.
26 *
27 * The above copyright notice and this permission notice (including the
28 * next paragraph) shall be included in all copies or substantial portions
29 * of the Software.
30 *
31 * Authors: Dave Airlie <airlied@redhat.com>
32 * Michael Thayer <michael.thayer@oracle.com,
33 * Hans de Goede <hdegoede@redhat.com>
34 */
35#include <linux/module.h>
36#include <linux/console.h>
37#include <linux/vt_kern.h>
38
39#include "vbox_drv.h"
40
41#include <drm/drm_crtc_helper.h>
42#if RTLNX_VER_MIN(5,1,0) || RTLNX_RHEL_MAJ_PREREQ(8,1)
43# include <drm/drm_probe_helper.h>
44#endif
45
46#if RTLNX_VER_MIN(5,14,0) || RTLNX_RHEL_RANGE(8,6, 8,99)
47# include <drm/drm_aperture.h>
48#endif
49
50#include "version-generated.h"
51#include "revision-generated.h"
52
53/** Detect whether kernel mode setting is OFF. */
54#if defined(CONFIG_VGA_CONSOLE)
55# if RTLNX_VER_MIN(5,17,0) || RTLNX_RHEL_RANGE(8,7, 8,99) || RTLNX_RHEL_MIN(9,1) || RTLNX_SUSE_MAJ_PREREQ(15,5)
56# define VBOX_VIDEO_NOMODESET() drm_firmware_drivers_only() && vbox_modeset == -1
57# elif RTLNX_VER_MIN(4,7,0)
58# define VBOX_VIDEO_NOMODESET() vgacon_text_force() && vbox_modeset == -1
59# else /* < 4.7.0 */
60# define VBOX_VIDEO_NOMODESET() 0
61# endif /* < 4.7.0 */
62#else /* !CONFIG_VGA_CONSOLE */
63# define VBOX_VIDEO_NOMODESET() 0
64#endif /* !CONFIG_VGA_CONSOLE */
65
66static int vbox_modeset = -1;
67
68MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
69module_param_named(modeset, vbox_modeset, int, 0400);
70
71static struct drm_driver driver;
72
73static const struct pci_device_id pciidlist[] = {
74 { 0x80ee, 0xbeef, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
75 { 0, 0, 0},
76};
77MODULE_DEVICE_TABLE(pci, pciidlist);
78
79static int vbox_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
80{
81#if RTLNX_VER_MIN(4,19,0) || RTLNX_RHEL_MIN(8,3)
82 struct drm_device *dev = NULL;
83 int ret = 0;
84
85# if RTLNX_VER_MIN(5,14,0) || RTLNX_RHEL_RANGE(8,6, 8,99)
86# if RTLNX_VER_MIN(5,15,0) || RTLNX_RHEL_RANGE(8,7, 8,99) || RTLNX_RHEL_MIN(9,1) || RTLNX_SUSE_MAJ_PREREQ(15,4)
87 ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, &driver);
88# else
89 ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, "vboxvideofb");
90# endif
91 if (ret)
92 {
93 printk("unable to remove conflicting framebuffer devices\n");
94 return ret;
95 }
96# endif /* >= 5.14. */
97
98 dev = drm_dev_alloc(&driver, &pdev->dev);
99 if (IS_ERR(dev)) {
100 ret = PTR_ERR(dev);
101 goto err_drv_alloc;
102 }
103# if RTLNX_VER_MAX(5,14,0) && !RTLNX_RHEL_RANGE(8,6, 8,99)
104 dev->pdev = pdev;
105# endif
106 pci_set_drvdata(pdev, dev);
107
108 ret = vbox_driver_load(dev);
109 if (ret)
110 goto err_vbox_driver_load;
111
112 ret = drm_dev_register(dev, 0);
113 if (ret)
114 goto err_drv_dev_register;
115 return ret;
116
117err_drv_dev_register:
118 vbox_driver_unload(dev);
119err_vbox_driver_load:
120 drm_dev_put(dev);
121err_drv_alloc:
122 return ret;
123#else /* < 4.19.0 || RHEL < 8.3 */
124 return drm_get_pci_dev(pdev, ent, &driver);
125#endif
126}
127
128static void vbox_pci_remove(struct pci_dev *pdev)
129{
130 struct drm_device *dev = pci_get_drvdata(pdev);
131
132#if RTLNX_VER_MAX(4,19,0)
133 drm_put_dev(dev);
134#else
135 drm_dev_unregister(dev);
136 vbox_driver_unload(dev);
137 drm_dev_put(dev);
138#endif
139}
140
141#if RTLNX_VER_MAX(4,9,0) && !RTLNX_RHEL_MAJ_PREREQ(7,4)
142static void drm_fb_helper_set_suspend_unlocked(struct drm_fb_helper *fb_helper,
143 bool suspend)
144{
145 if (!fb_helper || !fb_helper->fbdev)
146 return;
147
148 console_lock();
149 fb_set_suspend(fb_helper->fbdev, suspend);
150 console_unlock();
151}
152#endif
153
154static int vbox_drm_freeze(struct drm_device *dev)
155{
156 struct vbox_private *vbox = dev->dev_private;
157
158 drm_kms_helper_poll_disable(dev);
159
160 pci_save_state(VBOX_DRM_TO_PCI_DEV(dev));
161
162 drm_fb_helper_set_suspend_unlocked(&vbox->fbdev->helper, true);
163
164 return 0;
165}
166
167static int vbox_drm_thaw(struct drm_device *dev)
168{
169 struct vbox_private *vbox = dev->dev_private;
170
171 drm_mode_config_reset(dev);
172 drm_helper_resume_force_mode(dev);
173 drm_fb_helper_set_suspend_unlocked(&vbox->fbdev->helper, false);
174
175 return 0;
176}
177
178static int vbox_drm_resume(struct drm_device *dev)
179{
180 int ret;
181
182 if (pci_enable_device(VBOX_DRM_TO_PCI_DEV(dev)))
183 return -EIO;
184
185 ret = vbox_drm_thaw(dev);
186 if (ret)
187 return ret;
188
189 drm_kms_helper_poll_enable(dev);
190
191 return 0;
192}
193
194static int vbox_pm_suspend(struct device *dev)
195{
196 struct pci_dev *pdev = to_pci_dev(dev);
197 struct drm_device *ddev = pci_get_drvdata(pdev);
198 int error;
199
200 error = vbox_drm_freeze(ddev);
201 if (error)
202 return error;
203
204 pci_disable_device(pdev);
205 pci_set_power_state(pdev, PCI_D3hot);
206
207 return 0;
208}
209
210static int vbox_pm_resume(struct device *dev)
211{
212 struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
213
214 return vbox_drm_resume(ddev);
215}
216
217static int vbox_pm_freeze(struct device *dev)
218{
219 struct pci_dev *pdev = to_pci_dev(dev);
220 struct drm_device *ddev = pci_get_drvdata(pdev);
221
222 if (!ddev || !ddev->dev_private)
223 return -ENODEV;
224
225 return vbox_drm_freeze(ddev);
226}
227
228static int vbox_pm_thaw(struct device *dev)
229{
230 struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
231
232 return vbox_drm_thaw(ddev);
233}
234
235static int vbox_pm_poweroff(struct device *dev)
236{
237 struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
238
239 return vbox_drm_freeze(ddev);
240}
241
242static const struct dev_pm_ops vbox_pm_ops = {
243 .suspend = vbox_pm_suspend,
244 .resume = vbox_pm_resume,
245 .freeze = vbox_pm_freeze,
246 .thaw = vbox_pm_thaw,
247 .poweroff = vbox_pm_poweroff,
248 .restore = vbox_pm_resume,
249};
250
251static struct pci_driver vbox_pci_driver = {
252 .name = DRIVER_NAME,
253 .id_table = pciidlist,
254 .probe = vbox_pci_probe,
255 .remove = vbox_pci_remove,
256 .driver.pm = &vbox_pm_ops,
257};
258
259#if RTLNX_VER_MAX(4,7,0) && !RTLNX_RHEL_MAJ_PREREQ(7,4)
260/* This works around a bug in X servers prior to 1.18.4, which sometimes
261 * submit more dirty rectangles than the kernel is willing to handle and
262 * then disable dirty rectangle handling altogether when they see the
263 * EINVAL error. I do not want the code to hang around forever, which is
264 * why I am limiting it to certain kernel versions. We can increase the
265 * limit if some distributions uses old X servers with new kernels. */
266long vbox_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
267{
268 long rc = drm_ioctl(filp, cmd, arg);
269
270 if (cmd == DRM_IOCTL_MODE_DIRTYFB && rc == -EINVAL)
271 return -EOVERFLOW;
272
273 return rc;
274}
275#endif /* RTLNX_VER_MAX(4,7,0) && !RTLNX_RHEL_MAJ_PREREQ(7,4) */
276
277static const struct file_operations vbox_fops = {
278 .owner = THIS_MODULE,
279 .open = drm_open,
280 .release = drm_release,
281#if RTLNX_VER_MAX(4,7,0) && !RTLNX_RHEL_MAJ_PREREQ(7,4)
282 .unlocked_ioctl = vbox_ioctl,
283#else
284 .unlocked_ioctl = drm_ioctl,
285#endif
286 .mmap = vbox_mmap,
287 .poll = drm_poll,
288#if RTLNX_VER_MAX(3,12,0) && !RTLNX_RHEL_MAJ_PREREQ(7,0)
289 .fasync = drm_fasync,
290#endif
291#ifdef CONFIG_COMPAT
292 .compat_ioctl = drm_compat_ioctl,
293#endif
294 .read = drm_read,
295};
296
297#if RTLNX_VER_MIN(5,9,0) || RTLNX_RHEL_MIN(8,4) || RTLNX_SUSE_MAJ_PREREQ(15,3)
298static void
299#else
300static int
301#endif
302vbox_master_set(struct drm_device *dev,
303 struct drm_file *file_priv, bool from_open)
304{
305 struct vbox_private *vbox = dev->dev_private;
306
307 /*
308 * We do not yet know whether the new owner can handle hotplug, so we
309 * do not advertise dynamic modes on the first query and send a
310 * tentative hotplug notification after that to see if they query again.
311 */
312 vbox->initial_mode_queried = false;
313
314 mutex_lock(&vbox->hw_mutex);
315 /* Start the refresh timer in case the user does not provide dirty
316 * rectangles. */
317 vbox->need_refresh_timer = true;
318 schedule_delayed_work(&vbox->refresh_work, VBOX_REFRESH_PERIOD);
319 mutex_unlock(&vbox->hw_mutex);
320
321#if RTLNX_VER_MAX(5,9,0) && !RTLNX_RHEL_MAJ_PREREQ(8,4) && !RTLNX_SUSE_MAJ_PREREQ(15,3)
322 return 0;
323#endif
324}
325
326#if RTLNX_VER_MAX(4,8,0) && !RTLNX_RHEL_MAJ_PREREQ(7,4)
327static void vbox_master_drop(struct drm_device *dev,
328 struct drm_file *file_priv, bool from_release)
329#else
330static void vbox_master_drop(struct drm_device *dev, struct drm_file *file_priv)
331#endif
332{
333 struct vbox_private *vbox = dev->dev_private;
334
335 /* See vbox_master_set() */
336 vbox->initial_mode_queried = false;
337 vbox_report_caps(vbox);
338
339 mutex_lock(&vbox->hw_mutex);
340 vbox->need_refresh_timer = false;
341 mutex_unlock(&vbox->hw_mutex);
342}
343
344static struct drm_driver driver = {
345#if RTLNX_VER_MAX(5,4,0) && !RTLNX_RHEL_MAJ_PREREQ(8,3) && !RTLNX_SUSE_MAJ_PREREQ(15,3)
346 .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_HAVE_IRQ |
347# if RTLNX_VER_MAX(5,1,0) && !RTLNX_RHEL_MAJ_PREREQ(8,1)
348 DRIVER_IRQ_SHARED |
349# endif
350 DRIVER_PRIME,
351#else /* >= 5.4.0 && RHEL >= 8.3 && SLES >= 15-SP3 */
352 .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_HAVE_IRQ,
353#endif /* < 5.4.0 */
354
355#if RTLNX_VER_MAX(4,19,0) && !RTLNX_RHEL_MAJ_PREREQ(8,3)
356 /* Legacy hooks, but still supported. */
357 .load = vbox_driver_load,
358 .unload = vbox_driver_unload,
359#endif
360 .lastclose = vbox_driver_lastclose,
361 .master_set = vbox_master_set,
362 .master_drop = vbox_master_drop,
363#if RTLNX_VER_MIN(3,18,0) || RTLNX_RHEL_MAJ_PREREQ(7,2)
364# if RTLNX_VER_MAX(4,14,0) && !RTLNX_RHEL_MAJ_PREREQ(7,5) && !RTLNX_SUSE_MAJ_PREREQ(15,1) && !RTLNX_SUSE_MAJ_PREREQ(12,5)
365 .set_busid = drm_pci_set_busid,
366# endif
367#endif
368
369 .fops = &vbox_fops,
370#if RTLNX_VER_MAX(5,15,0) && !RTLNX_RHEL_RANGE(8,7, 8,99) && !RTLNX_RHEL_MAJ_PREREQ(9,1) && !RTLNX_SUSE_MAJ_PREREQ(15,5)
371 .irq_handler = vbox_irq_handler,
372#endif
373 .name = DRIVER_NAME,
374 .desc = DRIVER_DESC,
375 .date = DRIVER_DATE,
376 .major = DRIVER_MAJOR,
377 .minor = DRIVER_MINOR,
378 .patchlevel = DRIVER_PATCHLEVEL,
379
380#if RTLNX_VER_MAX(4,7,0)
381 .gem_free_object = vbox_gem_free_object,
382#endif
383 .dumb_create = vbox_dumb_create,
384 .dumb_map_offset = vbox_dumb_mmap_offset,
385#if RTLNX_VER_MAX(3,12,0) && !RTLNX_RHEL_MAJ_PREREQ(7,3)
386 .dumb_destroy = vbox_dumb_destroy,
387#elif RTLNX_VER_MAX(5,12,0) && !RTLNX_RHEL_MAJ_PREREQ(8,5)
388 .dumb_destroy = drm_gem_dumb_destroy,
389#endif
390#if RTLNX_VER_MAX(6,6,0) && !RTLNX_RHEL_RANGE(9,4, 9,99)
391 .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
392 .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
393#endif
394 .gem_prime_import = drm_gem_prime_import,
395 .gem_prime_import_sg_table = vbox_gem_prime_import_sg_table,
396#if RTLNX_VER_MAX(6,6,0) && !RTLNX_RHEL_RANGE(9,4, 9,99)
397 .gem_prime_mmap = vbox_gem_prime_mmap,
398#endif
399
400#if RTLNX_VER_MAX(5,11,0) && !RTLNX_RHEL_MAJ_PREREQ(8,5)
401 .dev_priv_size = 0,
402# if RTLNX_VER_MIN(4,7,0)
403 .gem_free_object_unlocked = vbox_gem_free_object,
404# endif
405 .gem_prime_export = drm_gem_prime_export,
406 .gem_prime_pin = vbox_gem_prime_pin,
407 .gem_prime_unpin = vbox_gem_prime_unpin,
408 .gem_prime_get_sg_table = vbox_gem_prime_get_sg_table,
409 .gem_prime_vmap = vbox_gem_prime_vmap,
410 .gem_prime_vunmap = vbox_gem_prime_vunmap,
411#endif
412};
413
414static int __init vbox_init(void)
415{
416 printk("vboxvideo: loading version " VBOX_VERSION_STRING " r" __stringify(VBOX_SVN_REV) "\n");
417 if (VBOX_VIDEO_NOMODESET())
418 {
419 printk("vboxvideo: kernel is running with *nomodeset* parameter,\n");
420 printk("vboxvideo: please consider either to remove it or load driver\n");
421 printk("vboxvideo: with parameter modeset=1, unloading\n");
422 return -EINVAL;
423 }
424
425 if (vbox_modeset == 0)
426 {
427 printk("vboxvideo: driver loaded with modeset=0 parameter, unloading\n");
428 return -EINVAL;
429 }
430
431#if RTLNX_VER_MIN(3,18,0) || RTLNX_RHEL_MAJ_PREREQ(7,3)
432 return pci_register_driver(&vbox_pci_driver);
433#else
434 return drm_pci_init(&driver, &vbox_pci_driver);
435#endif
436}
437
438static void __exit vbox_exit(void)
439{
440#if RTLNX_VER_MIN(3,18,0) || RTLNX_RHEL_MAJ_PREREQ(7,3)
441 pci_unregister_driver(&vbox_pci_driver);
442#else
443 drm_pci_exit(&driver, &vbox_pci_driver);
444#endif
445}
446
447module_init(vbox_init);
448module_exit(vbox_exit);
449
450MODULE_AUTHOR(DRIVER_AUTHOR);
451MODULE_DESCRIPTION(DRIVER_DESC);
452MODULE_LICENSE("GPL and additional rights");
453#ifdef MODULE_VERSION
454MODULE_VERSION(VBOX_VERSION_STRING " r" __stringify(VBOX_SVN_REV));
455#endif
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use