1 1.2 riastrad /* $NetBSD: qxl_drv.c,v 1.5 2021/12/18 23:45:42 riastradh Exp $ */ 2 1.2 riastrad 3 1.1 riastrad /* vim: set ts=8 sw=8 tw=78 ai noexpandtab */ 4 1.1 riastrad /* qxl_drv.c -- QXL driver -*- linux-c -*- 5 1.1 riastrad * 6 1.1 riastrad * Copyright 2011 Red Hat, Inc. 7 1.1 riastrad * All Rights Reserved. 8 1.1 riastrad * 9 1.1 riastrad * Permission is hereby granted, free of charge, to any person obtaining a 10 1.1 riastrad * copy of this software and associated documentation files (the "Software"), 11 1.1 riastrad * to deal in the Software without restriction, including without limitation 12 1.1 riastrad * the rights to use, copy, modify, merge, publish, distribute, sublicense, 13 1.1 riastrad * and/or sell copies of the Software, and to permit persons to whom the 14 1.1 riastrad * Software is furnished to do so, subject to the following conditions: 15 1.1 riastrad * 16 1.1 riastrad * The above copyright notice and this permission notice (including the next 17 1.1 riastrad * paragraph) shall be included in all copies or substantial portions of the 18 1.1 riastrad * Software. 19 1.1 riastrad * 20 1.1 riastrad * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 1.1 riastrad * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 1.1 riastrad * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 23 1.1 riastrad * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 24 1.1 riastrad * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 25 1.1 riastrad * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 26 1.1 riastrad * OTHER DEALINGS IN THE SOFTWARE. 27 1.1 riastrad * 28 1.1 riastrad * Authors: 29 1.1 riastrad * Dave Airlie <airlie (at) redhat.com> 30 1.1 riastrad * Alon Levy <alevy (at) redhat.com> 31 1.1 riastrad */ 32 1.1 riastrad 33 1.2 riastrad #include <sys/cdefs.h> 34 1.2 riastrad __KERNEL_RCSID(0, "$NetBSD: qxl_drv.c,v 1.5 2021/12/18 23:45:42 riastradh Exp $"); 35 1.2 riastrad 36 1.5 riastrad #include "qxl_drv.h" 37 1.5 riastrad #include <linux/console.h> 38 1.1 riastrad #include <linux/module.h> 39 1.5 riastrad #include <linux/pci.h> 40 1.5 riastrad 41 1.5 riastrad #include <drm/drm.h> 42 1.5 riastrad #include <drm/drm_drv.h> 43 1.5 riastrad #include <drm/drm_file.h> 44 1.5 riastrad #include <drm/drm_modeset_helper.h> 45 1.5 riastrad #include <drm/drm_prime.h> 46 1.5 riastrad #include <drm/drm_probe_helper.h> 47 1.1 riastrad 48 1.1 riastrad #include "qxl_object.h" 49 1.1 riastrad 50 1.2 riastrad static const struct pci_device_id pciidlist[] = { 51 1.1 riastrad { 0x1b36, 0x100, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 52 1.1 riastrad 0xffff00, 0 }, 53 1.1 riastrad { 0x1b36, 0x100, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_OTHER << 8, 54 1.1 riastrad 0xffff00, 0 }, 55 1.1 riastrad { 0, 0, 0 }, 56 1.1 riastrad }; 57 1.1 riastrad MODULE_DEVICE_TABLE(pci, pciidlist); 58 1.1 riastrad 59 1.1 riastrad static int qxl_modeset = -1; 60 1.1 riastrad int qxl_num_crtc = 4; 61 1.1 riastrad 62 1.1 riastrad MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); 63 1.1 riastrad module_param_named(modeset, qxl_modeset, int, 0400); 64 1.1 riastrad 65 1.1 riastrad MODULE_PARM_DESC(num_heads, "Number of virtual crtcs to expose (default 4)"); 66 1.1 riastrad module_param_named(num_heads, qxl_num_crtc, int, 0400); 67 1.1 riastrad 68 1.1 riastrad static struct drm_driver qxl_driver; 69 1.1 riastrad static struct pci_driver qxl_pci_driver; 70 1.1 riastrad 71 1.5 riastrad static bool is_vga(struct pci_dev *pdev) 72 1.5 riastrad { 73 1.5 riastrad return pdev->class == PCI_CLASS_DISPLAY_VGA << 8; 74 1.5 riastrad } 75 1.5 riastrad 76 1.1 riastrad static int 77 1.1 riastrad qxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 78 1.1 riastrad { 79 1.5 riastrad struct qxl_device *qdev; 80 1.5 riastrad int ret; 81 1.5 riastrad 82 1.1 riastrad if (pdev->revision < 4) { 83 1.1 riastrad DRM_ERROR("qxl too old, doesn't support client_monitors_config," 84 1.1 riastrad " use xf86-video-qxl in user mode"); 85 1.1 riastrad return -EINVAL; /* TODO: ENODEV ? */ 86 1.1 riastrad } 87 1.5 riastrad 88 1.5 riastrad qdev = kzalloc(sizeof(struct qxl_device), GFP_KERNEL); 89 1.5 riastrad if (!qdev) 90 1.5 riastrad return -ENOMEM; 91 1.5 riastrad 92 1.5 riastrad ret = pci_enable_device(pdev); 93 1.5 riastrad if (ret) 94 1.5 riastrad goto free_dev; 95 1.5 riastrad 96 1.5 riastrad ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "qxl"); 97 1.5 riastrad if (ret) 98 1.5 riastrad goto disable_pci; 99 1.5 riastrad 100 1.5 riastrad if (is_vga(pdev)) { 101 1.5 riastrad ret = vga_get_interruptible(pdev, VGA_RSRC_LEGACY_IO); 102 1.5 riastrad if (ret) { 103 1.5 riastrad DRM_ERROR("can't get legacy vga ioports\n"); 104 1.5 riastrad goto disable_pci; 105 1.5 riastrad } 106 1.5 riastrad } 107 1.5 riastrad 108 1.5 riastrad ret = qxl_device_init(qdev, &qxl_driver, pdev); 109 1.5 riastrad if (ret) 110 1.5 riastrad goto put_vga; 111 1.5 riastrad 112 1.5 riastrad ret = qxl_modeset_init(qdev); 113 1.5 riastrad if (ret) 114 1.5 riastrad goto unload; 115 1.5 riastrad 116 1.5 riastrad drm_kms_helper_poll_init(&qdev->ddev); 117 1.5 riastrad 118 1.5 riastrad /* Complete initialization. */ 119 1.5 riastrad ret = drm_dev_register(&qdev->ddev, ent->driver_data); 120 1.5 riastrad if (ret) 121 1.5 riastrad goto modeset_cleanup; 122 1.5 riastrad 123 1.5 riastrad drm_fbdev_generic_setup(&qdev->ddev, 32); 124 1.5 riastrad return 0; 125 1.5 riastrad 126 1.5 riastrad modeset_cleanup: 127 1.5 riastrad qxl_modeset_fini(qdev); 128 1.5 riastrad unload: 129 1.5 riastrad qxl_device_fini(qdev); 130 1.5 riastrad put_vga: 131 1.5 riastrad if (is_vga(pdev)) 132 1.5 riastrad vga_put(pdev, VGA_RSRC_LEGACY_IO); 133 1.5 riastrad disable_pci: 134 1.5 riastrad pci_disable_device(pdev); 135 1.5 riastrad free_dev: 136 1.5 riastrad kfree(qdev); 137 1.5 riastrad return ret; 138 1.1 riastrad } 139 1.1 riastrad 140 1.1 riastrad static void 141 1.1 riastrad qxl_pci_remove(struct pci_dev *pdev) 142 1.1 riastrad { 143 1.1 riastrad struct drm_device *dev = pci_get_drvdata(pdev); 144 1.5 riastrad struct qxl_device *qdev = dev->dev_private; 145 1.5 riastrad 146 1.5 riastrad drm_dev_unregister(dev); 147 1.5 riastrad 148 1.5 riastrad qxl_modeset_fini(qdev); 149 1.5 riastrad qxl_device_fini(qdev); 150 1.5 riastrad if (is_vga(pdev)) 151 1.5 riastrad vga_put(pdev, VGA_RSRC_LEGACY_IO); 152 1.1 riastrad 153 1.5 riastrad dev->dev_private = NULL; 154 1.5 riastrad kfree(qdev); 155 1.5 riastrad drm_dev_put(dev); 156 1.1 riastrad } 157 1.1 riastrad 158 1.5 riastrad DEFINE_DRM_GEM_FOPS(qxl_fops); 159 1.1 riastrad 160 1.1 riastrad static int qxl_drm_freeze(struct drm_device *dev) 161 1.1 riastrad { 162 1.1 riastrad struct pci_dev *pdev = dev->pdev; 163 1.1 riastrad struct qxl_device *qdev = dev->dev_private; 164 1.5 riastrad int ret; 165 1.1 riastrad 166 1.5 riastrad ret = drm_mode_config_helper_suspend(dev); 167 1.5 riastrad if (ret) 168 1.5 riastrad return ret; 169 1.1 riastrad 170 1.1 riastrad qxl_destroy_monitors_object(qdev); 171 1.1 riastrad qxl_surf_evict(qdev); 172 1.1 riastrad qxl_vram_evict(qdev); 173 1.1 riastrad 174 1.1 riastrad while (!qxl_check_idle(qdev->command_ring)); 175 1.1 riastrad while (!qxl_check_idle(qdev->release_ring)) 176 1.1 riastrad qxl_queue_garbage_collect(qdev, 1); 177 1.1 riastrad 178 1.1 riastrad pci_save_state(pdev); 179 1.1 riastrad 180 1.1 riastrad return 0; 181 1.1 riastrad } 182 1.1 riastrad 183 1.1 riastrad static int qxl_drm_resume(struct drm_device *dev, bool thaw) 184 1.1 riastrad { 185 1.1 riastrad struct qxl_device *qdev = dev->dev_private; 186 1.1 riastrad 187 1.1 riastrad qdev->ram_header->int_mask = QXL_INTERRUPT_MASK; 188 1.1 riastrad if (!thaw) { 189 1.1 riastrad qxl_reinit_memslots(qdev); 190 1.1 riastrad qxl_ring_init_hdr(qdev->release_ring); 191 1.1 riastrad } 192 1.1 riastrad 193 1.1 riastrad qxl_create_monitors_object(qdev); 194 1.5 riastrad return drm_mode_config_helper_resume(dev); 195 1.1 riastrad } 196 1.1 riastrad 197 1.1 riastrad static int qxl_pm_suspend(struct device *dev) 198 1.1 riastrad { 199 1.1 riastrad struct pci_dev *pdev = to_pci_dev(dev); 200 1.1 riastrad struct drm_device *drm_dev = pci_get_drvdata(pdev); 201 1.1 riastrad int error; 202 1.1 riastrad 203 1.1 riastrad error = qxl_drm_freeze(drm_dev); 204 1.1 riastrad if (error) 205 1.1 riastrad return error; 206 1.1 riastrad 207 1.1 riastrad pci_disable_device(pdev); 208 1.1 riastrad pci_set_power_state(pdev, PCI_D3hot); 209 1.1 riastrad return 0; 210 1.1 riastrad } 211 1.1 riastrad 212 1.1 riastrad static int qxl_pm_resume(struct device *dev) 213 1.1 riastrad { 214 1.1 riastrad struct pci_dev *pdev = to_pci_dev(dev); 215 1.1 riastrad struct drm_device *drm_dev = pci_get_drvdata(pdev); 216 1.1 riastrad 217 1.1 riastrad pci_set_power_state(pdev, PCI_D0); 218 1.1 riastrad pci_restore_state(pdev); 219 1.1 riastrad if (pci_enable_device(pdev)) { 220 1.1 riastrad return -EIO; 221 1.1 riastrad } 222 1.1 riastrad 223 1.1 riastrad return qxl_drm_resume(drm_dev, false); 224 1.1 riastrad } 225 1.1 riastrad 226 1.1 riastrad static int qxl_pm_thaw(struct device *dev) 227 1.1 riastrad { 228 1.5 riastrad struct drm_device *drm_dev = dev_get_drvdata(dev); 229 1.1 riastrad 230 1.1 riastrad return qxl_drm_resume(drm_dev, true); 231 1.1 riastrad } 232 1.1 riastrad 233 1.1 riastrad static int qxl_pm_freeze(struct device *dev) 234 1.1 riastrad { 235 1.5 riastrad struct drm_device *drm_dev = dev_get_drvdata(dev); 236 1.1 riastrad 237 1.1 riastrad return qxl_drm_freeze(drm_dev); 238 1.1 riastrad } 239 1.1 riastrad 240 1.1 riastrad static int qxl_pm_restore(struct device *dev) 241 1.1 riastrad { 242 1.1 riastrad struct pci_dev *pdev = to_pci_dev(dev); 243 1.1 riastrad struct drm_device *drm_dev = pci_get_drvdata(pdev); 244 1.1 riastrad struct qxl_device *qdev = drm_dev->dev_private; 245 1.1 riastrad 246 1.1 riastrad qxl_io_reset(qdev); 247 1.1 riastrad return qxl_drm_resume(drm_dev, false); 248 1.1 riastrad } 249 1.1 riastrad 250 1.1 riastrad static const struct dev_pm_ops qxl_pm_ops = { 251 1.1 riastrad .suspend = qxl_pm_suspend, 252 1.1 riastrad .resume = qxl_pm_resume, 253 1.1 riastrad .freeze = qxl_pm_freeze, 254 1.1 riastrad .thaw = qxl_pm_thaw, 255 1.1 riastrad .poweroff = qxl_pm_freeze, 256 1.1 riastrad .restore = qxl_pm_restore, 257 1.1 riastrad }; 258 1.1 riastrad static struct pci_driver qxl_pci_driver = { 259 1.1 riastrad .name = DRIVER_NAME, 260 1.1 riastrad .id_table = pciidlist, 261 1.1 riastrad .probe = qxl_pci_probe, 262 1.1 riastrad .remove = qxl_pci_remove, 263 1.1 riastrad .driver.pm = &qxl_pm_ops, 264 1.1 riastrad }; 265 1.1 riastrad 266 1.1 riastrad static struct drm_driver qxl_driver = { 267 1.5 riastrad .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, 268 1.1 riastrad 269 1.1 riastrad .dumb_create = qxl_mode_dumb_create, 270 1.1 riastrad .dumb_map_offset = qxl_mode_dumb_mmap, 271 1.1 riastrad #if defined(CONFIG_DEBUG_FS) 272 1.1 riastrad .debugfs_init = qxl_debugfs_init, 273 1.1 riastrad #endif 274 1.2 riastrad .prime_handle_to_fd = drm_gem_prime_handle_to_fd, 275 1.2 riastrad .prime_fd_to_handle = drm_gem_prime_fd_to_handle, 276 1.2 riastrad .gem_prime_import_sg_table = qxl_gem_prime_import_sg_table, 277 1.2 riastrad .gem_prime_mmap = qxl_gem_prime_mmap, 278 1.1 riastrad .fops = &qxl_fops, 279 1.1 riastrad .ioctls = qxl_ioctls, 280 1.1 riastrad .irq_handler = qxl_irq_handler, 281 1.3 riastrad #ifdef __NetBSD__ 282 1.3 riastrad .request_irq = drm_pci_request_irq, 283 1.3 riastrad .free_irq = drm_pci_free_irq, 284 1.3 riastrad #endif 285 1.1 riastrad .name = DRIVER_NAME, 286 1.1 riastrad .desc = DRIVER_DESC, 287 1.1 riastrad .date = DRIVER_DATE, 288 1.1 riastrad .major = 0, 289 1.1 riastrad .minor = 1, 290 1.1 riastrad .patchlevel = 0, 291 1.1 riastrad }; 292 1.1 riastrad 293 1.1 riastrad static int __init qxl_init(void) 294 1.1 riastrad { 295 1.1 riastrad if (vgacon_text_force() && qxl_modeset == -1) 296 1.1 riastrad return -EINVAL; 297 1.1 riastrad 298 1.1 riastrad if (qxl_modeset == 0) 299 1.1 riastrad return -EINVAL; 300 1.1 riastrad qxl_driver.num_ioctls = qxl_max_ioctls; 301 1.5 riastrad return pci_register_driver(&qxl_pci_driver); 302 1.1 riastrad } 303 1.1 riastrad 304 1.1 riastrad static void __exit qxl_exit(void) 305 1.1 riastrad { 306 1.5 riastrad pci_unregister_driver(&qxl_pci_driver); 307 1.1 riastrad } 308 1.1 riastrad 309 1.1 riastrad module_init(qxl_init); 310 1.1 riastrad module_exit(qxl_exit); 311 1.1 riastrad 312 1.1 riastrad MODULE_AUTHOR(DRIVER_AUTHOR); 313 1.1 riastrad MODULE_DESCRIPTION(DRIVER_DESC); 314 1.1 riastrad MODULE_LICENSE("GPL and additional rights"); 315