VirtualBox

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

最後變更 在這個檔案從90577是 90577,由 vboxsync 提交於 4 年 前

Linux Host and Guest drivers: another attempt to introduce initial support for RHEL 8.5 kernels, bugref:4567.

CentOS kernel 4.18.0-326.el8 (RHEL 8,5) has backported commits from vanilla kernel 5.10+.
Fedora kernel 5.9.0-36.eln104 (RHEL 8,99) does not have some of these changes yet.
This commit attempts to move relevant code into RHEL 8,5 specific section. For some
parts of DRM code, changes are only affect RHEL 8,5 (8,99 is excluded) due to missing
commits (on 8,99) from newer kernels.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 11.5 KB
 
1/* $Id: vbox_drv.c 90577 2021-08-09 09:57:00Z vboxsync $ */
2/** @file
3 * VirtualBox Additions Linux kernel video driver
4 */
5
6/*
7 * Copyright (C) 2013-2020 Oracle Corporation
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 <[email protected]>
32 * Michael Thayer <[email protected],
33 * Hans de Goede <[email protected]>
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)
47# include <drm/drm_aperture.h>
48#endif
49
50#include "version-generated.h"
51#include "revision-generated.h"
52
53static int vbox_modeset = -1;
54
55MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
56module_param_named(modeset, vbox_modeset, int, 0400);
57
58static struct drm_driver driver;
59
60static const struct pci_device_id pciidlist[] = {
61 { 0x80ee, 0xbeef, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
62 { 0, 0, 0},
63};
64MODULE_DEVICE_TABLE(pci, pciidlist);
65
66static int vbox_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
67{
68#if RTLNX_VER_MIN(4,19,0) || RTLNX_RHEL_MIN(8,3)
69 struct drm_device *dev = NULL;
70 int ret = 0;
71
72# if RTLNX_VER_MIN(5,14,0)
73 ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, "vboxvideofb");
74 if (ret)
75 {
76 printk("unable to remove conflicting framebuffer devices\n");
77 return ret;
78 }
79# endif /* 5.14 */
80
81 dev = drm_dev_alloc(&driver, &pdev->dev);
82 if (IS_ERR(dev)) {
83 ret = PTR_ERR(dev);
84 goto err_drv_alloc;
85 }
86#if RTLNX_VER_MAX(5,14,0)
87 dev->pdev = pdev;
88#endif
89 pci_set_drvdata(pdev, dev);
90
91 ret = vbox_driver_load(dev);
92 if (ret)
93 goto err_vbox_driver_load;
94
95 ret = drm_dev_register(dev, 0);
96 if (ret)
97 goto err_drv_dev_register;
98 return ret;
99
100err_drv_dev_register:
101 vbox_driver_unload(dev);
102err_vbox_driver_load:
103 drm_dev_put(dev);
104err_drv_alloc:
105 return ret;
106#else /* < 4.19.0 || RHEL < 8.3 */
107 return drm_get_pci_dev(pdev, ent, &driver);
108#endif
109}
110
111static void vbox_pci_remove(struct pci_dev *pdev)
112{
113 struct drm_device *dev = pci_get_drvdata(pdev);
114
115#if RTLNX_VER_MAX(4,19,0)
116 drm_put_dev(dev);
117#else
118 drm_dev_unregister(dev);
119 vbox_driver_unload(dev);
120 drm_dev_put(dev);
121#endif
122}
123
124#if RTLNX_VER_MAX(4,9,0) && !RTLNX_RHEL_MAJ_PREREQ(7,4)
125static void drm_fb_helper_set_suspend_unlocked(struct drm_fb_helper *fb_helper,
126 bool suspend)
127{
128 if (!fb_helper || !fb_helper->fbdev)
129 return;
130
131 console_lock();
132 fb_set_suspend(fb_helper->fbdev, suspend);
133 console_unlock();
134}
135#endif
136
137static int vbox_drm_freeze(struct drm_device *dev)
138{
139 struct vbox_private *vbox = dev->dev_private;
140
141 drm_kms_helper_poll_disable(dev);
142
143 pci_save_state(VBOX_DRM_TO_PCI_DEV(dev));
144
145 drm_fb_helper_set_suspend_unlocked(&vbox->fbdev->helper, true);
146
147 return 0;
148}
149
150static int vbox_drm_thaw(struct drm_device *dev)
151{
152 struct vbox_private *vbox = dev->dev_private;
153
154 drm_mode_config_reset(dev);
155 drm_helper_resume_force_mode(dev);
156 drm_fb_helper_set_suspend_unlocked(&vbox->fbdev->helper, false);
157
158 return 0;
159}
160
161static int vbox_drm_resume(struct drm_device *dev)
162{
163 int ret;
164
165 if (pci_enable_device(VBOX_DRM_TO_PCI_DEV(dev)))
166 return -EIO;
167
168 ret = vbox_drm_thaw(dev);
169 if (ret)
170 return ret;
171
172 drm_kms_helper_poll_enable(dev);
173
174 return 0;
175}
176
177static int vbox_pm_suspend(struct device *dev)
178{
179 struct pci_dev *pdev = to_pci_dev(dev);
180 struct drm_device *ddev = pci_get_drvdata(pdev);
181 int error;
182
183 error = vbox_drm_freeze(ddev);
184 if (error)
185 return error;
186
187 pci_disable_device(pdev);
188 pci_set_power_state(pdev, PCI_D3hot);
189
190 return 0;
191}
192
193static int vbox_pm_resume(struct device *dev)
194{
195 struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
196
197 return vbox_drm_resume(ddev);
198}
199
200static int vbox_pm_freeze(struct device *dev)
201{
202 struct pci_dev *pdev = to_pci_dev(dev);
203 struct drm_device *ddev = pci_get_drvdata(pdev);
204
205 if (!ddev || !ddev->dev_private)
206 return -ENODEV;
207
208 return vbox_drm_freeze(ddev);
209}
210
211static int vbox_pm_thaw(struct device *dev)
212{
213 struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
214
215 return vbox_drm_thaw(ddev);
216}
217
218static int vbox_pm_poweroff(struct device *dev)
219{
220 struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
221
222 return vbox_drm_freeze(ddev);
223}
224
225static const struct dev_pm_ops vbox_pm_ops = {
226 .suspend = vbox_pm_suspend,
227 .resume = vbox_pm_resume,
228 .freeze = vbox_pm_freeze,
229 .thaw = vbox_pm_thaw,
230 .poweroff = vbox_pm_poweroff,
231 .restore = vbox_pm_resume,
232};
233
234static struct pci_driver vbox_pci_driver = {
235 .name = DRIVER_NAME,
236 .id_table = pciidlist,
237 .probe = vbox_pci_probe,
238 .remove = vbox_pci_remove,
239 .driver.pm = &vbox_pm_ops,
240};
241
242#if RTLNX_VER_MAX(4,7,0) && !RTLNX_RHEL_MAJ_PREREQ(7,4)
243/* This works around a bug in X servers prior to 1.18.4, which sometimes
244 * submit more dirty rectangles than the kernel is willing to handle and
245 * then disable dirty rectangle handling altogether when they see the
246 * EINVAL error. I do not want the code to hang around forever, which is
247 * why I am limiting it to certain kernel versions. We can increase the
248 * limit if some distributions uses old X servers with new kernels. */
249long vbox_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
250{
251 long rc = drm_ioctl(filp, cmd, arg);
252
253 if (cmd == DRM_IOCTL_MODE_DIRTYFB && rc == -EINVAL)
254 return -EOVERFLOW;
255
256 return rc;
257}
258#endif /* RTLNX_VER_MAX(4,7,0) && !RTLNX_RHEL_MAJ_PREREQ(7,4) */
259
260static const struct file_operations vbox_fops = {
261 .owner = THIS_MODULE,
262 .open = drm_open,
263 .release = drm_release,
264#if RTLNX_VER_MAX(4,7,0) && !RTLNX_RHEL_MAJ_PREREQ(7,4)
265 .unlocked_ioctl = vbox_ioctl,
266#else
267 .unlocked_ioctl = drm_ioctl,
268#endif
269 .mmap = vbox_mmap,
270 .poll = drm_poll,
271#if RTLNX_VER_MAX(3,12,0) && !RTLNX_RHEL_MAJ_PREREQ(7,0)
272 .fasync = drm_fasync,
273#endif
274#ifdef CONFIG_COMPAT
275 .compat_ioctl = drm_compat_ioctl,
276#endif
277 .read = drm_read,
278};
279
280#if RTLNX_VER_MIN(5,9,0) || RTLNX_RHEL_MIN(8,4) || RTLNX_SUSE_MAJ_PREREQ(15,3)
281static void
282#else
283static int
284#endif
285vbox_master_set(struct drm_device *dev,
286 struct drm_file *file_priv, bool from_open)
287{
288 struct vbox_private *vbox = dev->dev_private;
289
290 /*
291 * We do not yet know whether the new owner can handle hotplug, so we
292 * do not advertise dynamic modes on the first query and send a
293 * tentative hotplug notification after that to see if they query again.
294 */
295 vbox->initial_mode_queried = false;
296
297 mutex_lock(&vbox->hw_mutex);
298 /* Start the refresh timer in case the user does not provide dirty
299 * rectangles. */
300 vbox->need_refresh_timer = true;
301 schedule_delayed_work(&vbox->refresh_work, VBOX_REFRESH_PERIOD);
302 mutex_unlock(&vbox->hw_mutex);
303
304#if RTLNX_VER_MAX(5,9,0) && !RTLNX_RHEL_MAJ_PREREQ(8,4) && !RTLNX_SUSE_MAJ_PREREQ(15,3)
305 return 0;
306#endif
307}
308
309#if RTLNX_VER_MAX(4,8,0) && !RTLNX_RHEL_MAJ_PREREQ(7,4)
310static void vbox_master_drop(struct drm_device *dev,
311 struct drm_file *file_priv, bool from_release)
312#else
313static void vbox_master_drop(struct drm_device *dev, struct drm_file *file_priv)
314#endif
315{
316 struct vbox_private *vbox = dev->dev_private;
317
318 /* See vbox_master_set() */
319 vbox->initial_mode_queried = false;
320 vbox_report_caps(vbox);
321
322 mutex_lock(&vbox->hw_mutex);
323 vbox->need_refresh_timer = false;
324 mutex_unlock(&vbox->hw_mutex);
325}
326
327static struct drm_driver driver = {
328#if RTLNX_VER_MAX(5,4,0) && !RTLNX_RHEL_MAJ_PREREQ(8,3) && !RTLNX_SUSE_MAJ_PREREQ(15,3)
329 .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_HAVE_IRQ |
330# if RTLNX_VER_MAX(5,1,0) && !RTLNX_RHEL_MAJ_PREREQ(8,1)
331 DRIVER_IRQ_SHARED |
332# endif
333 DRIVER_PRIME,
334#else /* >= 5.4.0 && RHEL >= 8.3 && SLES >= 15-SP3 */
335 .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_HAVE_IRQ,
336#endif /* < 5.4.0 */
337
338#if RTLNX_VER_MAX(4,19,0) && !RTLNX_RHEL_MAJ_PREREQ(8,3)
339 /* Legacy hooks, but still supported. */
340 .load = vbox_driver_load,
341 .unload = vbox_driver_unload,
342#endif
343 .lastclose = vbox_driver_lastclose,
344 .master_set = vbox_master_set,
345 .master_drop = vbox_master_drop,
346#if RTLNX_VER_MIN(3,18,0) || RTLNX_RHEL_MAJ_PREREQ(7,2)
347# 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)
348 .set_busid = drm_pci_set_busid,
349# endif
350#endif
351
352 .fops = &vbox_fops,
353 .irq_handler = vbox_irq_handler,
354 .name = DRIVER_NAME,
355 .desc = DRIVER_DESC,
356 .date = DRIVER_DATE,
357 .major = DRIVER_MAJOR,
358 .minor = DRIVER_MINOR,
359 .patchlevel = DRIVER_PATCHLEVEL,
360
361#if RTLNX_VER_MAX(4,7,0)
362 .gem_free_object = vbox_gem_free_object,
363#endif
364 .dumb_create = vbox_dumb_create,
365 .dumb_map_offset = vbox_dumb_mmap_offset,
366#if RTLNX_VER_MAX(3,12,0) && !RTLNX_RHEL_MAJ_PREREQ(7,3)
367 .dumb_destroy = vbox_dumb_destroy,
368#elif RTLNX_VER_MAX(5,12,0) && !RTLNX_RHEL_MAJ_PREREQ(8,5)
369 .dumb_destroy = drm_gem_dumb_destroy,
370#endif
371 .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
372 .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
373
374 .gem_prime_import = drm_gem_prime_import,
375 .gem_prime_import_sg_table = vbox_gem_prime_import_sg_table,
376 .gem_prime_mmap = vbox_gem_prime_mmap,
377
378#if RTLNX_VER_MAX(5,11,0) && !RTLNX_RHEL_MAJ_PREREQ(8,5)
379 .dev_priv_size = 0,
380# if RTLNX_VER_MIN(4,7,0)
381 .gem_free_object_unlocked = vbox_gem_free_object,
382# endif
383 .gem_prime_export = drm_gem_prime_export,
384 .gem_prime_pin = vbox_gem_prime_pin,
385 .gem_prime_unpin = vbox_gem_prime_unpin,
386 .gem_prime_get_sg_table = vbox_gem_prime_get_sg_table,
387 .gem_prime_vmap = vbox_gem_prime_vmap,
388 .gem_prime_vunmap = vbox_gem_prime_vunmap,
389#endif
390};
391
392static int __init vbox_init(void)
393{
394 printk("vboxvideo: loading version " VBOX_VERSION_STRING " r" __stringify(VBOX_SVN_REV) "\n");
395#if defined(CONFIG_VGA_CONSOLE) || RTLNX_VER_MIN(4,7,0)
396 if (vgacon_text_force() && vbox_modeset == -1)
397 {
398 printk("vboxvideo: kernel is running with *nomodeset* parameter,\n");
399 printk("vboxvideo: please consider either to remove it or load driver\n");
400 printk("vboxvideo: with parameter modeset=1, unloading\n");
401 return -EINVAL;
402 }
403#endif
404
405 if (vbox_modeset == 0)
406 {
407 printk("vboxvideo: driver loaded with modeset=0 parameter, unloading\n");
408 return -EINVAL;
409 }
410
411#if RTLNX_VER_MIN(3,18,0) || RTLNX_RHEL_MAJ_PREREQ(7,3)
412 return pci_register_driver(&vbox_pci_driver);
413#else
414 return drm_pci_init(&driver, &vbox_pci_driver);
415#endif
416}
417
418static void __exit vbox_exit(void)
419{
420#if RTLNX_VER_MIN(3,18,0) || RTLNX_RHEL_MAJ_PREREQ(7,3)
421 pci_unregister_driver(&vbox_pci_driver);
422#else
423 drm_pci_exit(&driver, &vbox_pci_driver);
424#endif
425}
426
427module_init(vbox_init);
428module_exit(vbox_exit);
429
430MODULE_AUTHOR(DRIVER_AUTHOR);
431MODULE_DESCRIPTION(DRIVER_DESC);
432MODULE_LICENSE("GPL and additional rights");
433#ifdef MODULE_VERSION
434MODULE_VERSION(VBOX_VERSION_STRING " r" __stringify(VBOX_SVN_REV));
435#endif
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette