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