Back to home page

OSCL-LXR

 
 

    


0001 /* qxl_drv.c -- QXL driver -*- linux-c -*-
0002  *
0003  * Copyright 2011 Red Hat, Inc.
0004  * All Rights Reserved.
0005  *
0006  * Permission is hereby granted, free of charge, to any person obtaining a
0007  * copy of this software and associated documentation files (the "Software"),
0008  * to deal in the Software without restriction, including without limitation
0009  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0010  * and/or sell copies of the Software, and to permit persons to whom the
0011  * Software is furnished to do so, subject to the following conditions:
0012  *
0013  * The above copyright notice and this permission notice (including the next
0014  * paragraph) shall be included in all copies or substantial portions of the
0015  * Software.
0016  *
0017  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0018  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0019  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0020  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
0021  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0022  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0023  * OTHER DEALINGS IN THE SOFTWARE.
0024  *
0025  * Authors:
0026  *    Dave Airlie <airlie@redhat.com>
0027  *    Alon Levy <alevy@redhat.com>
0028  */
0029 
0030 #include "qxl_drv.h"
0031 
0032 #include <linux/module.h>
0033 #include <linux/pci.h>
0034 #include <linux/vgaarb.h>
0035 
0036 #include <drm/drm.h>
0037 #include <drm/drm_aperture.h>
0038 #include <drm/drm_atomic_helper.h>
0039 #include <drm/drm_drv.h>
0040 #include <drm/drm_file.h>
0041 #include <drm/drm_gem_ttm_helper.h>
0042 #include <drm/drm_module.h>
0043 #include <drm/drm_modeset_helper.h>
0044 #include <drm/drm_prime.h>
0045 #include <drm/drm_probe_helper.h>
0046 
0047 #include "qxl_object.h"
0048 
0049 static const struct pci_device_id pciidlist[] = {
0050     { 0x1b36, 0x100, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8,
0051       0xffff00, 0 },
0052     { 0x1b36, 0x100, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_OTHER << 8,
0053       0xffff00, 0 },
0054     { 0, 0, 0 },
0055 };
0056 MODULE_DEVICE_TABLE(pci, pciidlist);
0057 
0058 static int qxl_modeset = -1;
0059 int qxl_num_crtc = 4;
0060 
0061 MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
0062 module_param_named(modeset, qxl_modeset, int, 0400);
0063 
0064 MODULE_PARM_DESC(num_heads, "Number of virtual crtcs to expose (default 4)");
0065 module_param_named(num_heads, qxl_num_crtc, int, 0400);
0066 
0067 static struct drm_driver qxl_driver;
0068 static struct pci_driver qxl_pci_driver;
0069 
0070 static bool is_vga(struct pci_dev *pdev)
0071 {
0072     return pdev->class == PCI_CLASS_DISPLAY_VGA << 8;
0073 }
0074 
0075 static int
0076 qxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
0077 {
0078     struct qxl_device *qdev;
0079     int ret;
0080 
0081     if (pdev->revision < 4) {
0082         DRM_ERROR("qxl too old, doesn't support client_monitors_config,"
0083               " use xf86-video-qxl in user mode");
0084         return -EINVAL; /* TODO: ENODEV ? */
0085     }
0086 
0087     qdev = devm_drm_dev_alloc(&pdev->dev, &qxl_driver,
0088                   struct qxl_device, ddev);
0089     if (IS_ERR(qdev)) {
0090         pr_err("Unable to init drm dev");
0091         return -ENOMEM;
0092     }
0093 
0094     ret = pci_enable_device(pdev);
0095     if (ret)
0096         return ret;
0097 
0098     ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, &qxl_driver);
0099     if (ret)
0100         goto disable_pci;
0101 
0102     if (is_vga(pdev) && pdev->revision < 5) {
0103         ret = vga_get_interruptible(pdev, VGA_RSRC_LEGACY_IO);
0104         if (ret) {
0105             DRM_ERROR("can't get legacy vga ioports\n");
0106             goto disable_pci;
0107         }
0108     }
0109 
0110     ret = qxl_device_init(qdev, pdev);
0111     if (ret)
0112         goto put_vga;
0113 
0114     ret = qxl_modeset_init(qdev);
0115     if (ret)
0116         goto unload;
0117 
0118     drm_kms_helper_poll_init(&qdev->ddev);
0119 
0120     /* Complete initialization. */
0121     ret = drm_dev_register(&qdev->ddev, ent->driver_data);
0122     if (ret)
0123         goto modeset_cleanup;
0124 
0125     drm_fbdev_generic_setup(&qdev->ddev, 32);
0126     return 0;
0127 
0128 modeset_cleanup:
0129     qxl_modeset_fini(qdev);
0130 unload:
0131     qxl_device_fini(qdev);
0132 put_vga:
0133     if (is_vga(pdev) && pdev->revision < 5)
0134         vga_put(pdev, VGA_RSRC_LEGACY_IO);
0135 disable_pci:
0136     pci_disable_device(pdev);
0137 
0138     return ret;
0139 }
0140 
0141 static void qxl_drm_release(struct drm_device *dev)
0142 {
0143     struct qxl_device *qdev = to_qxl(dev);
0144 
0145     /*
0146      * TODO: qxl_device_fini() call should be in qxl_pci_remove(),
0147      * reordering qxl_modeset_fini() + qxl_device_fini() calls is
0148      * non-trivial though.
0149      */
0150     qxl_modeset_fini(qdev);
0151     qxl_device_fini(qdev);
0152 }
0153 
0154 static void
0155 qxl_pci_remove(struct pci_dev *pdev)
0156 {
0157     struct drm_device *dev = pci_get_drvdata(pdev);
0158 
0159     drm_dev_unregister(dev);
0160     drm_atomic_helper_shutdown(dev);
0161     if (is_vga(pdev) && pdev->revision < 5)
0162         vga_put(pdev, VGA_RSRC_LEGACY_IO);
0163 }
0164 
0165 DEFINE_DRM_GEM_FOPS(qxl_fops);
0166 
0167 static int qxl_drm_freeze(struct drm_device *dev)
0168 {
0169     struct pci_dev *pdev = to_pci_dev(dev->dev);
0170     struct qxl_device *qdev = to_qxl(dev);
0171     int ret;
0172 
0173     ret = drm_mode_config_helper_suspend(dev);
0174     if (ret)
0175         return ret;
0176 
0177     qxl_destroy_monitors_object(qdev);
0178     qxl_surf_evict(qdev);
0179     qxl_vram_evict(qdev);
0180 
0181     while (!qxl_check_idle(qdev->command_ring));
0182     while (!qxl_check_idle(qdev->release_ring))
0183         qxl_queue_garbage_collect(qdev, 1);
0184 
0185     pci_save_state(pdev);
0186 
0187     return 0;
0188 }
0189 
0190 static int qxl_drm_resume(struct drm_device *dev, bool thaw)
0191 {
0192     struct qxl_device *qdev = to_qxl(dev);
0193 
0194     qdev->ram_header->int_mask = QXL_INTERRUPT_MASK;
0195     if (!thaw) {
0196         qxl_reinit_memslots(qdev);
0197         qxl_ring_init_hdr(qdev->release_ring);
0198     }
0199 
0200     qxl_create_monitors_object(qdev);
0201     return drm_mode_config_helper_resume(dev);
0202 }
0203 
0204 static int qxl_pm_suspend(struct device *dev)
0205 {
0206     struct pci_dev *pdev = to_pci_dev(dev);
0207     struct drm_device *drm_dev = pci_get_drvdata(pdev);
0208     int error;
0209 
0210     error = qxl_drm_freeze(drm_dev);
0211     if (error)
0212         return error;
0213 
0214     pci_disable_device(pdev);
0215     pci_set_power_state(pdev, PCI_D3hot);
0216     return 0;
0217 }
0218 
0219 static int qxl_pm_resume(struct device *dev)
0220 {
0221     struct pci_dev *pdev = to_pci_dev(dev);
0222     struct drm_device *drm_dev = pci_get_drvdata(pdev);
0223 
0224     pci_set_power_state(pdev, PCI_D0);
0225     pci_restore_state(pdev);
0226     if (pci_enable_device(pdev)) {
0227         return -EIO;
0228     }
0229 
0230     return qxl_drm_resume(drm_dev, false);
0231 }
0232 
0233 static int qxl_pm_thaw(struct device *dev)
0234 {
0235     struct drm_device *drm_dev = dev_get_drvdata(dev);
0236 
0237     return qxl_drm_resume(drm_dev, true);
0238 }
0239 
0240 static int qxl_pm_freeze(struct device *dev)
0241 {
0242     struct drm_device *drm_dev = dev_get_drvdata(dev);
0243 
0244     return qxl_drm_freeze(drm_dev);
0245 }
0246 
0247 static int qxl_pm_restore(struct device *dev)
0248 {
0249     struct pci_dev *pdev = to_pci_dev(dev);
0250     struct drm_device *drm_dev = pci_get_drvdata(pdev);
0251     struct qxl_device *qdev = to_qxl(drm_dev);
0252 
0253     qxl_io_reset(qdev);
0254     return qxl_drm_resume(drm_dev, false);
0255 }
0256 
0257 static const struct dev_pm_ops qxl_pm_ops = {
0258     .suspend = qxl_pm_suspend,
0259     .resume = qxl_pm_resume,
0260     .freeze = qxl_pm_freeze,
0261     .thaw = qxl_pm_thaw,
0262     .poweroff = qxl_pm_freeze,
0263     .restore = qxl_pm_restore,
0264 };
0265 static struct pci_driver qxl_pci_driver = {
0266      .name = DRIVER_NAME,
0267      .id_table = pciidlist,
0268      .probe = qxl_pci_probe,
0269      .remove = qxl_pci_remove,
0270      .driver.pm = &qxl_pm_ops,
0271 };
0272 
0273 static const struct drm_ioctl_desc qxl_ioctls[] = {
0274     DRM_IOCTL_DEF_DRV(QXL_ALLOC, qxl_alloc_ioctl, DRM_AUTH),
0275     DRM_IOCTL_DEF_DRV(QXL_MAP, qxl_map_ioctl, DRM_AUTH),
0276     DRM_IOCTL_DEF_DRV(QXL_EXECBUFFER, qxl_execbuffer_ioctl, DRM_AUTH),
0277     DRM_IOCTL_DEF_DRV(QXL_UPDATE_AREA, qxl_update_area_ioctl, DRM_AUTH),
0278     DRM_IOCTL_DEF_DRV(QXL_GETPARAM, qxl_getparam_ioctl, DRM_AUTH),
0279     DRM_IOCTL_DEF_DRV(QXL_CLIENTCAP, qxl_clientcap_ioctl, DRM_AUTH),
0280     DRM_IOCTL_DEF_DRV(QXL_ALLOC_SURF, qxl_alloc_surf_ioctl, DRM_AUTH),
0281 };
0282 
0283 static struct drm_driver qxl_driver = {
0284     .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
0285 
0286     .dumb_create = qxl_mode_dumb_create,
0287     .dumb_map_offset = drm_gem_ttm_dumb_map_offset,
0288 #if defined(CONFIG_DEBUG_FS)
0289     .debugfs_init = qxl_debugfs_init,
0290 #endif
0291     .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
0292     .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
0293     .gem_prime_import_sg_table = qxl_gem_prime_import_sg_table,
0294     .fops = &qxl_fops,
0295     .ioctls = qxl_ioctls,
0296     .num_ioctls = ARRAY_SIZE(qxl_ioctls),
0297     .name = DRIVER_NAME,
0298     .desc = DRIVER_DESC,
0299     .date = DRIVER_DATE,
0300     .major = 0,
0301     .minor = 1,
0302     .patchlevel = 0,
0303 
0304     .release = qxl_drm_release,
0305 };
0306 
0307 drm_module_pci_driver_if_modeset(qxl_pci_driver, qxl_modeset);
0308 
0309 MODULE_AUTHOR(DRIVER_AUTHOR);
0310 MODULE_DESCRIPTION(DRIVER_DESC);
0311 MODULE_LICENSE("GPL and additional rights");