19edbd4a0SFrançois Tigeot /* 2*24edb884SFrançois Tigeot * Created: Fri Jan 19 10:48:35 2001 by faith@acm.org 39edbd4a0SFrançois Tigeot * 4*24edb884SFrançois Tigeot * Copyright 2001 VA Linux Systems, Inc., Sunnyvale, California. 57f3c3d6fSHasso Tepper * All Rights Reserved. 67f3c3d6fSHasso Tepper * 7*24edb884SFrançois Tigeot * Author Rickard E. (Rik) Faith <faith@valinux.com> 8*24edb884SFrançois Tigeot * 97f3c3d6fSHasso Tepper * Permission is hereby granted, free of charge, to any person obtaining a 107f3c3d6fSHasso Tepper * copy of this software and associated documentation files (the "Software"), 117f3c3d6fSHasso Tepper * to deal in the Software without restriction, including without limitation 127f3c3d6fSHasso Tepper * the rights to use, copy, modify, merge, publish, distribute, sublicense, 137f3c3d6fSHasso Tepper * and/or sell copies of the Software, and to permit persons to whom the 147f3c3d6fSHasso Tepper * Software is furnished to do so, subject to the following conditions: 157f3c3d6fSHasso Tepper * 167f3c3d6fSHasso Tepper * The above copyright notice and this permission notice (including the next 177f3c3d6fSHasso Tepper * paragraph) shall be included in all copies or substantial portions of the 187f3c3d6fSHasso Tepper * Software. 197f3c3d6fSHasso Tepper * 207f3c3d6fSHasso Tepper * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 217f3c3d6fSHasso Tepper * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 227f3c3d6fSHasso Tepper * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 23*24edb884SFrançois Tigeot * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 247f3c3d6fSHasso Tepper * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 25*24edb884SFrançois Tigeot * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26*24edb884SFrançois Tigeot * DEALINGS IN THE SOFTWARE. 277f3c3d6fSHasso Tepper */ 287f3c3d6fSHasso Tepper 29*24edb884SFrançois Tigeot #include <linux/module.h> 30*24edb884SFrançois Tigeot #include <linux/moduleparam.h> 31*24edb884SFrançois Tigeot #include <drm/drmP.h> 32*24edb884SFrançois Tigeot #include <drm/drm_core.h> 33*24edb884SFrançois Tigeot #include "drm_legacy.h" 34*24edb884SFrançois Tigeot 35*24edb884SFrançois Tigeot unsigned int drm_debug = 0; /* 1 to enable debug output */ 36*24edb884SFrançois Tigeot EXPORT_SYMBOL(drm_debug); 37*24edb884SFrançois Tigeot 38*24edb884SFrançois Tigeot unsigned int drm_vblank_offdelay = 5000; /* Default to 5000 msecs. */ 39*24edb884SFrançois Tigeot 40*24edb884SFrançois Tigeot unsigned int drm_timestamp_precision = 20; /* Default to 20 usecs. */ 41*24edb884SFrançois Tigeot 42*24edb884SFrançois Tigeot /* 43*24edb884SFrançois Tigeot * Default to use monotonic timestamps for wait-for-vblank and page-flip 44*24edb884SFrançois Tigeot * complete events. 45*24edb884SFrançois Tigeot */ 46*24edb884SFrançois Tigeot unsigned int drm_timestamp_monotonic = 1; 47*24edb884SFrançois Tigeot 48*24edb884SFrançois Tigeot MODULE_AUTHOR(CORE_AUTHOR); 49*24edb884SFrançois Tigeot MODULE_DESCRIPTION(CORE_DESC); 50*24edb884SFrançois Tigeot MODULE_LICENSE("GPL and additional rights"); 51*24edb884SFrançois Tigeot MODULE_PARM_DESC(debug, "Enable debug output"); 52*24edb884SFrançois Tigeot MODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs]"); 53*24edb884SFrançois Tigeot MODULE_PARM_DESC(timestamp_precision_usec, "Max. error on timestamps [usecs]"); 54*24edb884SFrançois Tigeot MODULE_PARM_DESC(timestamp_monotonic, "Use monotonic timestamps"); 55*24edb884SFrançois Tigeot 56*24edb884SFrançois Tigeot module_param_named(debug, drm_debug, int, 0600); 57*24edb884SFrançois Tigeot module_param_named(vblankoffdelay, drm_vblank_offdelay, int, 0600); 58*24edb884SFrançois Tigeot module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600); 59*24edb884SFrançois Tigeot module_param_named(timestamp_monotonic, drm_timestamp_monotonic, int, 0600); 60*24edb884SFrançois Tigeot 61*24edb884SFrançois Tigeot #if 0 62*24edb884SFrançois Tigeot static DEFINE_SPINLOCK(drm_minor_lock); 63*24edb884SFrançois Tigeot static struct idr drm_minors_idr; 64*24edb884SFrançois Tigeot #endif 65*24edb884SFrançois Tigeot 66*24edb884SFrançois Tigeot struct class *drm_class; 67*24edb884SFrançois Tigeot #if 0 68*24edb884SFrançois Tigeot static struct dentry *drm_debugfs_root; 69*24edb884SFrançois Tigeot #endif 70*24edb884SFrançois Tigeot 71*24edb884SFrançois Tigeot int drm_err(const char *func, const char *format, ...) 72*24edb884SFrançois Tigeot { 73*24edb884SFrançois Tigeot #if 0 74*24edb884SFrançois Tigeot struct va_format vaf; 75*24edb884SFrançois Tigeot va_list args; 76*24edb884SFrançois Tigeot int r; 77*24edb884SFrançois Tigeot 78*24edb884SFrançois Tigeot va_start(args, format); 79*24edb884SFrançois Tigeot 80*24edb884SFrançois Tigeot vaf.fmt = format; 81*24edb884SFrançois Tigeot vaf.va = &args; 82*24edb884SFrançois Tigeot 83*24edb884SFrançois Tigeot r = printk(KERN_ERR "[" DRM_NAME ":%s] *ERROR* %pV", func, &vaf); 84*24edb884SFrançois Tigeot 85*24edb884SFrançois Tigeot va_end(args); 86*24edb884SFrançois Tigeot 87*24edb884SFrançois Tigeot return r; 88*24edb884SFrançois Tigeot #endif 89*24edb884SFrançois Tigeot return 0; 90*24edb884SFrançois Tigeot } 91*24edb884SFrançois Tigeot EXPORT_SYMBOL(drm_err); 92*24edb884SFrançois Tigeot 93*24edb884SFrançois Tigeot void drm_ut_debug_printk(const char *function_name, const char *format, ...) 94*24edb884SFrançois Tigeot { 95*24edb884SFrançois Tigeot #if 0 96*24edb884SFrançois Tigeot struct va_format vaf; 97*24edb884SFrançois Tigeot va_list args; 98*24edb884SFrançois Tigeot 99*24edb884SFrançois Tigeot va_start(args, format); 100*24edb884SFrançois Tigeot vaf.fmt = format; 101*24edb884SFrançois Tigeot vaf.va = &args; 102*24edb884SFrançois Tigeot 103*24edb884SFrançois Tigeot printk(KERN_DEBUG "[" DRM_NAME ":%s] %pV", function_name, &vaf); 104*24edb884SFrançois Tigeot 105*24edb884SFrançois Tigeot va_end(args); 106*24edb884SFrançois Tigeot #endif 107*24edb884SFrançois Tigeot } 108*24edb884SFrançois Tigeot EXPORT_SYMBOL(drm_ut_debug_printk); 109*24edb884SFrançois Tigeot 110*24edb884SFrançois Tigeot #if 0 111*24edb884SFrançois Tigeot struct drm_master *drm_master_create(struct drm_minor *minor) 112*24edb884SFrançois Tigeot { 113*24edb884SFrançois Tigeot struct drm_master *master; 114*24edb884SFrançois Tigeot 115*24edb884SFrançois Tigeot master = kzalloc(sizeof(*master), GFP_KERNEL); 116*24edb884SFrançois Tigeot if (!master) 117*24edb884SFrançois Tigeot return NULL; 118*24edb884SFrançois Tigeot 119*24edb884SFrançois Tigeot kref_init(&master->refcount); 120*24edb884SFrançois Tigeot spin_lock_init(&master->lock.spinlock); 121*24edb884SFrançois Tigeot init_waitqueue_head(&master->lock.lock_queue); 122*24edb884SFrançois Tigeot if (drm_ht_create(&master->magiclist, DRM_MAGIC_HASH_ORDER)) { 123*24edb884SFrançois Tigeot kfree(master); 124*24edb884SFrançois Tigeot return NULL; 125*24edb884SFrançois Tigeot } 126*24edb884SFrançois Tigeot INIT_LIST_HEAD(&master->magicfree); 127*24edb884SFrançois Tigeot master->minor = minor; 128*24edb884SFrançois Tigeot 129*24edb884SFrançois Tigeot return master; 130*24edb884SFrançois Tigeot } 131*24edb884SFrançois Tigeot 132*24edb884SFrançois Tigeot struct drm_master *drm_master_get(struct drm_master *master) 133*24edb884SFrançois Tigeot { 134*24edb884SFrançois Tigeot kref_get(&master->refcount); 135*24edb884SFrançois Tigeot return master; 136*24edb884SFrançois Tigeot } 137*24edb884SFrançois Tigeot EXPORT_SYMBOL(drm_master_get); 138*24edb884SFrançois Tigeot 139*24edb884SFrançois Tigeot static void drm_master_destroy(struct kref *kref) 140*24edb884SFrançois Tigeot { 141*24edb884SFrançois Tigeot struct drm_master *master = container_of(kref, struct drm_master, refcount); 142*24edb884SFrançois Tigeot struct drm_magic_entry *pt, *next; 143*24edb884SFrançois Tigeot struct drm_device *dev = master->minor->dev; 144*24edb884SFrançois Tigeot struct drm_map_list *r_list, *list_temp; 145*24edb884SFrançois Tigeot 146*24edb884SFrançois Tigeot mutex_lock(&dev->struct_mutex); 147*24edb884SFrançois Tigeot if (dev->driver->master_destroy) 148*24edb884SFrançois Tigeot dev->driver->master_destroy(dev, master); 149*24edb884SFrançois Tigeot 150*24edb884SFrançois Tigeot list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head) { 151*24edb884SFrançois Tigeot if (r_list->master == master) { 152*24edb884SFrançois Tigeot drm_rmmap_locked(dev, r_list->map); 153*24edb884SFrançois Tigeot r_list = NULL; 154*24edb884SFrançois Tigeot } 155*24edb884SFrançois Tigeot } 156*24edb884SFrançois Tigeot 157*24edb884SFrançois Tigeot if (master->unique) { 158*24edb884SFrançois Tigeot kfree(master->unique); 159*24edb884SFrançois Tigeot master->unique = NULL; 160*24edb884SFrançois Tigeot master->unique_len = 0; 161*24edb884SFrançois Tigeot } 162*24edb884SFrançois Tigeot 163*24edb884SFrançois Tigeot list_for_each_entry_safe(pt, next, &master->magicfree, head) { 164*24edb884SFrançois Tigeot list_del(&pt->head); 165*24edb884SFrançois Tigeot drm_ht_remove_item(&master->magiclist, &pt->hash_item); 166*24edb884SFrançois Tigeot kfree(pt); 167*24edb884SFrançois Tigeot } 168*24edb884SFrançois Tigeot 169*24edb884SFrançois Tigeot drm_ht_remove(&master->magiclist); 170*24edb884SFrançois Tigeot 171*24edb884SFrançois Tigeot mutex_unlock(&dev->struct_mutex); 172*24edb884SFrançois Tigeot kfree(master); 173*24edb884SFrançois Tigeot } 174*24edb884SFrançois Tigeot 175*24edb884SFrançois Tigeot void drm_master_put(struct drm_master **master) 176*24edb884SFrançois Tigeot { 177*24edb884SFrançois Tigeot kref_put(&(*master)->refcount, drm_master_destroy); 178*24edb884SFrançois Tigeot *master = NULL; 179*24edb884SFrançois Tigeot } 180*24edb884SFrançois Tigeot EXPORT_SYMBOL(drm_master_put); 181*24edb884SFrançois Tigeot #endif 182*24edb884SFrançois Tigeot 183*24edb884SFrançois Tigeot int drm_setmaster_ioctl(struct drm_device *dev, void *data, 184*24edb884SFrançois Tigeot struct drm_file *file_priv) 185*24edb884SFrançois Tigeot { 186*24edb884SFrançois Tigeot DRM_DEBUG("setmaster\n"); 187*24edb884SFrançois Tigeot 188*24edb884SFrançois Tigeot if (file_priv->master != 0) 189*24edb884SFrançois Tigeot return (0); 190*24edb884SFrançois Tigeot 191*24edb884SFrançois Tigeot return (-EPERM); 192*24edb884SFrançois Tigeot } 193*24edb884SFrançois Tigeot 194*24edb884SFrançois Tigeot int drm_dropmaster_ioctl(struct drm_device *dev, void *data, 195*24edb884SFrançois Tigeot struct drm_file *file_priv) 196*24edb884SFrançois Tigeot { 197*24edb884SFrançois Tigeot DRM_DEBUG("dropmaster\n"); 198*24edb884SFrançois Tigeot if (file_priv->master != 0) 199*24edb884SFrançois Tigeot return -EINVAL; 200*24edb884SFrançois Tigeot return 0; 201*24edb884SFrançois Tigeot } 202*24edb884SFrançois Tigeot 203*24edb884SFrançois Tigeot #if 0 204*24edb884SFrançois Tigeot /* 205*24edb884SFrançois Tigeot * DRM Minors 206*24edb884SFrançois Tigeot * A DRM device can provide several char-dev interfaces on the DRM-Major. Each 207*24edb884SFrançois Tigeot * of them is represented by a drm_minor object. Depending on the capabilities 208*24edb884SFrançois Tigeot * of the device-driver, different interfaces are registered. 209*24edb884SFrançois Tigeot * 210*24edb884SFrançois Tigeot * Minors can be accessed via dev->$minor_name. This pointer is either 211*24edb884SFrançois Tigeot * NULL or a valid drm_minor pointer and stays valid as long as the device is 212*24edb884SFrançois Tigeot * valid. This means, DRM minors have the same life-time as the underlying 213*24edb884SFrançois Tigeot * device. However, this doesn't mean that the minor is active. Minors are 214*24edb884SFrançois Tigeot * registered and unregistered dynamically according to device-state. 215*24edb884SFrançois Tigeot */ 216*24edb884SFrançois Tigeot 217*24edb884SFrançois Tigeot static struct drm_minor **drm_minor_get_slot(struct drm_device *dev, 218*24edb884SFrançois Tigeot unsigned int type) 219*24edb884SFrançois Tigeot { 220*24edb884SFrançois Tigeot switch (type) { 221*24edb884SFrançois Tigeot case DRM_MINOR_LEGACY: 222*24edb884SFrançois Tigeot return &dev->primary; 223*24edb884SFrançois Tigeot case DRM_MINOR_RENDER: 224*24edb884SFrançois Tigeot return &dev->render; 225*24edb884SFrançois Tigeot case DRM_MINOR_CONTROL: 226*24edb884SFrançois Tigeot return &dev->control; 227*24edb884SFrançois Tigeot default: 228*24edb884SFrançois Tigeot return NULL; 229*24edb884SFrançois Tigeot } 230*24edb884SFrançois Tigeot } 231*24edb884SFrançois Tigeot 232*24edb884SFrançois Tigeot static int drm_minor_alloc(struct drm_device *dev, unsigned int type) 233*24edb884SFrançois Tigeot { 234*24edb884SFrançois Tigeot struct drm_minor *minor; 235*24edb884SFrançois Tigeot unsigned long flags; 236*24edb884SFrançois Tigeot int r; 237*24edb884SFrançois Tigeot 238*24edb884SFrançois Tigeot minor = kzalloc(sizeof(*minor), GFP_KERNEL); 239*24edb884SFrançois Tigeot if (!minor) 240*24edb884SFrançois Tigeot return -ENOMEM; 241*24edb884SFrançois Tigeot 242*24edb884SFrançois Tigeot minor->type = type; 243*24edb884SFrançois Tigeot minor->dev = dev; 244*24edb884SFrançois Tigeot 245*24edb884SFrançois Tigeot idr_preload(GFP_KERNEL); 246*24edb884SFrançois Tigeot spin_lock_irqsave(&drm_minor_lock, flags); 247*24edb884SFrançois Tigeot r = idr_alloc(&drm_minors_idr, 248*24edb884SFrançois Tigeot NULL, 249*24edb884SFrançois Tigeot 64 * type, 250*24edb884SFrançois Tigeot 64 * (type + 1), 251*24edb884SFrançois Tigeot GFP_NOWAIT); 252*24edb884SFrançois Tigeot spin_unlock_irqrestore(&drm_minor_lock, flags); 253*24edb884SFrançois Tigeot idr_preload_end(); 254*24edb884SFrançois Tigeot 255*24edb884SFrançois Tigeot if (r < 0) 256*24edb884SFrançois Tigeot goto err_free; 257*24edb884SFrançois Tigeot 258*24edb884SFrançois Tigeot minor->index = r; 259*24edb884SFrançois Tigeot 260*24edb884SFrançois Tigeot minor->kdev = drm_sysfs_minor_alloc(minor); 261*24edb884SFrançois Tigeot if (IS_ERR(minor->kdev)) { 262*24edb884SFrançois Tigeot r = PTR_ERR(minor->kdev); 263*24edb884SFrançois Tigeot goto err_index; 264*24edb884SFrançois Tigeot } 265*24edb884SFrançois Tigeot 266*24edb884SFrançois Tigeot *drm_minor_get_slot(dev, type) = minor; 267*24edb884SFrançois Tigeot return 0; 268*24edb884SFrançois Tigeot 269*24edb884SFrançois Tigeot err_index: 270*24edb884SFrançois Tigeot spin_lock_irqsave(&drm_minor_lock, flags); 271*24edb884SFrançois Tigeot idr_remove(&drm_minors_idr, minor->index); 272*24edb884SFrançois Tigeot spin_unlock_irqrestore(&drm_minor_lock, flags); 273*24edb884SFrançois Tigeot err_free: 274*24edb884SFrançois Tigeot kfree(minor); 275*24edb884SFrançois Tigeot return r; 276*24edb884SFrançois Tigeot } 277*24edb884SFrançois Tigeot 278*24edb884SFrançois Tigeot static void drm_minor_free(struct drm_device *dev, unsigned int type) 279*24edb884SFrançois Tigeot { 280*24edb884SFrançois Tigeot struct drm_minor **slot, *minor; 281*24edb884SFrançois Tigeot unsigned long flags; 282*24edb884SFrançois Tigeot 283*24edb884SFrançois Tigeot slot = drm_minor_get_slot(dev, type); 284*24edb884SFrançois Tigeot minor = *slot; 285*24edb884SFrançois Tigeot if (!minor) 286*24edb884SFrançois Tigeot return; 287*24edb884SFrançois Tigeot 288*24edb884SFrançois Tigeot drm_mode_group_destroy(&minor->mode_group); 289*24edb884SFrançois Tigeot put_device(minor->kdev); 290*24edb884SFrançois Tigeot 291*24edb884SFrançois Tigeot spin_lock_irqsave(&drm_minor_lock, flags); 292*24edb884SFrançois Tigeot idr_remove(&drm_minors_idr, minor->index); 293*24edb884SFrançois Tigeot spin_unlock_irqrestore(&drm_minor_lock, flags); 294*24edb884SFrançois Tigeot 295*24edb884SFrançois Tigeot kfree(minor); 296*24edb884SFrançois Tigeot *slot = NULL; 297*24edb884SFrançois Tigeot } 298*24edb884SFrançois Tigeot 299*24edb884SFrançois Tigeot static int drm_minor_register(struct drm_device *dev, unsigned int type) 300*24edb884SFrançois Tigeot { 301*24edb884SFrançois Tigeot struct drm_minor *minor; 302*24edb884SFrançois Tigeot unsigned long flags; 303*24edb884SFrançois Tigeot int ret; 304*24edb884SFrançois Tigeot 305*24edb884SFrançois Tigeot DRM_DEBUG("\n"); 306*24edb884SFrançois Tigeot 307*24edb884SFrançois Tigeot minor = *drm_minor_get_slot(dev, type); 308*24edb884SFrançois Tigeot if (!minor) 309*24edb884SFrançois Tigeot return 0; 310*24edb884SFrançois Tigeot 311*24edb884SFrançois Tigeot ret = drm_debugfs_init(minor, minor->index, drm_debugfs_root); 312*24edb884SFrançois Tigeot if (ret) { 313*24edb884SFrançois Tigeot DRM_ERROR("DRM: Failed to initialize /sys/kernel/debug/dri.\n"); 314*24edb884SFrançois Tigeot return ret; 315*24edb884SFrançois Tigeot } 316*24edb884SFrançois Tigeot 317*24edb884SFrançois Tigeot ret = device_add(minor->kdev); 318*24edb884SFrançois Tigeot if (ret) 319*24edb884SFrançois Tigeot goto err_debugfs; 320*24edb884SFrançois Tigeot 321*24edb884SFrançois Tigeot /* replace NULL with @minor so lookups will succeed from now on */ 322*24edb884SFrançois Tigeot spin_lock_irqsave(&drm_minor_lock, flags); 323*24edb884SFrançois Tigeot idr_replace(&drm_minors_idr, minor, minor->index); 324*24edb884SFrançois Tigeot spin_unlock_irqrestore(&drm_minor_lock, flags); 325*24edb884SFrançois Tigeot 326*24edb884SFrançois Tigeot DRM_DEBUG("new minor registered %d\n", minor->index); 327*24edb884SFrançois Tigeot return 0; 328*24edb884SFrançois Tigeot 329*24edb884SFrançois Tigeot err_debugfs: 330*24edb884SFrançois Tigeot drm_debugfs_cleanup(minor); 331*24edb884SFrançois Tigeot return ret; 332*24edb884SFrançois Tigeot } 333*24edb884SFrançois Tigeot 334*24edb884SFrançois Tigeot static void drm_minor_unregister(struct drm_device *dev, unsigned int type) 335*24edb884SFrançois Tigeot { 336*24edb884SFrançois Tigeot struct drm_minor *minor; 337*24edb884SFrançois Tigeot unsigned long flags; 338*24edb884SFrançois Tigeot 339*24edb884SFrançois Tigeot minor = *drm_minor_get_slot(dev, type); 340*24edb884SFrançois Tigeot if (!minor || !device_is_registered(minor->kdev)) 341*24edb884SFrançois Tigeot return; 342*24edb884SFrançois Tigeot 343*24edb884SFrançois Tigeot /* replace @minor with NULL so lookups will fail from now on */ 344*24edb884SFrançois Tigeot spin_lock_irqsave(&drm_minor_lock, flags); 345*24edb884SFrançois Tigeot idr_replace(&drm_minors_idr, NULL, minor->index); 346*24edb884SFrançois Tigeot spin_unlock_irqrestore(&drm_minor_lock, flags); 347*24edb884SFrançois Tigeot 348*24edb884SFrançois Tigeot device_del(minor->kdev); 349*24edb884SFrançois Tigeot dev_set_drvdata(minor->kdev, NULL); /* safety belt */ 350*24edb884SFrançois Tigeot drm_debugfs_cleanup(minor); 351*24edb884SFrançois Tigeot } 352*24edb884SFrançois Tigeot 353*24edb884SFrançois Tigeot /** 354*24edb884SFrançois Tigeot * drm_minor_acquire - Acquire a DRM minor 355*24edb884SFrançois Tigeot * @minor_id: Minor ID of the DRM-minor 356*24edb884SFrançois Tigeot * 357*24edb884SFrançois Tigeot * Looks up the given minor-ID and returns the respective DRM-minor object. The 358*24edb884SFrançois Tigeot * refence-count of the underlying device is increased so you must release this 359*24edb884SFrançois Tigeot * object with drm_minor_release(). 360*24edb884SFrançois Tigeot * 361*24edb884SFrançois Tigeot * As long as you hold this minor, it is guaranteed that the object and the 362*24edb884SFrançois Tigeot * minor->dev pointer will stay valid! However, the device may get unplugged and 363*24edb884SFrançois Tigeot * unregistered while you hold the minor. 364*24edb884SFrançois Tigeot * 365*24edb884SFrançois Tigeot * Returns: 366*24edb884SFrançois Tigeot * Pointer to minor-object with increased device-refcount, or PTR_ERR on 367*24edb884SFrançois Tigeot * failure. 368*24edb884SFrançois Tigeot */ 369*24edb884SFrançois Tigeot struct drm_minor *drm_minor_acquire(unsigned int minor_id) 370*24edb884SFrançois Tigeot { 371*24edb884SFrançois Tigeot struct drm_minor *minor; 372*24edb884SFrançois Tigeot unsigned long flags; 373*24edb884SFrançois Tigeot 374*24edb884SFrançois Tigeot spin_lock_irqsave(&drm_minor_lock, flags); 375*24edb884SFrançois Tigeot minor = idr_find(&drm_minors_idr, minor_id); 376*24edb884SFrançois Tigeot if (minor) 377*24edb884SFrançois Tigeot drm_dev_ref(minor->dev); 378*24edb884SFrançois Tigeot spin_unlock_irqrestore(&drm_minor_lock, flags); 379*24edb884SFrançois Tigeot 380*24edb884SFrançois Tigeot if (!minor) { 381*24edb884SFrançois Tigeot return ERR_PTR(-ENODEV); 382*24edb884SFrançois Tigeot } else if (drm_device_is_unplugged(minor->dev)) { 383*24edb884SFrançois Tigeot drm_dev_unref(minor->dev); 384*24edb884SFrançois Tigeot return ERR_PTR(-ENODEV); 385*24edb884SFrançois Tigeot } 386*24edb884SFrançois Tigeot 387*24edb884SFrançois Tigeot return minor; 388*24edb884SFrançois Tigeot } 389*24edb884SFrançois Tigeot 390*24edb884SFrançois Tigeot /** 391*24edb884SFrançois Tigeot * drm_minor_release - Release DRM minor 392*24edb884SFrançois Tigeot * @minor: Pointer to DRM minor object 393*24edb884SFrançois Tigeot * 394*24edb884SFrançois Tigeot * Release a minor that was previously acquired via drm_minor_acquire(). 395*24edb884SFrançois Tigeot */ 396*24edb884SFrançois Tigeot void drm_minor_release(struct drm_minor *minor) 397*24edb884SFrançois Tigeot { 398*24edb884SFrançois Tigeot drm_dev_unref(minor->dev); 399*24edb884SFrançois Tigeot } 400*24edb884SFrançois Tigeot 401*24edb884SFrançois Tigeot /** 402*24edb884SFrançois Tigeot * drm_put_dev - Unregister and release a DRM device 403*24edb884SFrançois Tigeot * @dev: DRM device 404*24edb884SFrançois Tigeot * 405*24edb884SFrançois Tigeot * Called at module unload time or when a PCI device is unplugged. 406*24edb884SFrançois Tigeot * 407*24edb884SFrançois Tigeot * Use of this function is discouraged. It will eventually go away completely. 408*24edb884SFrançois Tigeot * Please use drm_dev_unregister() and drm_dev_unref() explicitly instead. 409*24edb884SFrançois Tigeot * 410*24edb884SFrançois Tigeot * Cleans up all DRM device, calling drm_lastclose(). 411*24edb884SFrançois Tigeot */ 412*24edb884SFrançois Tigeot void drm_put_dev(struct drm_device *dev) 413*24edb884SFrançois Tigeot { 414*24edb884SFrançois Tigeot DRM_DEBUG("\n"); 415*24edb884SFrançois Tigeot 416*24edb884SFrançois Tigeot if (!dev) { 417*24edb884SFrançois Tigeot DRM_ERROR("cleanup called no dev\n"); 418*24edb884SFrançois Tigeot return; 419*24edb884SFrançois Tigeot } 420*24edb884SFrançois Tigeot 421*24edb884SFrançois Tigeot drm_dev_unregister(dev); 422*24edb884SFrançois Tigeot drm_dev_unref(dev); 423*24edb884SFrançois Tigeot } 424*24edb884SFrançois Tigeot EXPORT_SYMBOL(drm_put_dev); 425*24edb884SFrançois Tigeot 426*24edb884SFrançois Tigeot void drm_unplug_dev(struct drm_device *dev) 427*24edb884SFrançois Tigeot { 428*24edb884SFrançois Tigeot /* for a USB device */ 429*24edb884SFrançois Tigeot drm_minor_unregister(dev, DRM_MINOR_LEGACY); 430*24edb884SFrançois Tigeot drm_minor_unregister(dev, DRM_MINOR_RENDER); 431*24edb884SFrançois Tigeot drm_minor_unregister(dev, DRM_MINOR_CONTROL); 432*24edb884SFrançois Tigeot 433*24edb884SFrançois Tigeot mutex_lock(&drm_global_mutex); 434*24edb884SFrançois Tigeot 435*24edb884SFrançois Tigeot drm_device_set_unplugged(dev); 436*24edb884SFrançois Tigeot 437*24edb884SFrançois Tigeot if (dev->open_count == 0) { 438*24edb884SFrançois Tigeot drm_put_dev(dev); 439*24edb884SFrançois Tigeot } 440*24edb884SFrançois Tigeot mutex_unlock(&drm_global_mutex); 441*24edb884SFrançois Tigeot } 442*24edb884SFrançois Tigeot EXPORT_SYMBOL(drm_unplug_dev); 443*24edb884SFrançois Tigeot 444*24edb884SFrançois Tigeot /* 445*24edb884SFrançois Tigeot * DRM internal mount 446*24edb884SFrançois Tigeot * We want to be able to allocate our own "struct address_space" to control 447*24edb884SFrançois Tigeot * memory-mappings in VRAM (or stolen RAM, ...). However, core MM does not allow 448*24edb884SFrançois Tigeot * stand-alone address_space objects, so we need an underlying inode. As there 449*24edb884SFrançois Tigeot * is no way to allocate an independent inode easily, we need a fake internal 450*24edb884SFrançois Tigeot * VFS mount-point. 451*24edb884SFrançois Tigeot * 452*24edb884SFrançois Tigeot * The drm_fs_inode_new() function allocates a new inode, drm_fs_inode_free() 453*24edb884SFrançois Tigeot * frees it again. You are allowed to use iget() and iput() to get references to 454*24edb884SFrançois Tigeot * the inode. But each drm_fs_inode_new() call must be paired with exactly one 455*24edb884SFrançois Tigeot * drm_fs_inode_free() call (which does not have to be the last iput()). 456*24edb884SFrançois Tigeot * We use drm_fs_inode_*() to manage our internal VFS mount-point and share it 457*24edb884SFrançois Tigeot * between multiple inode-users. You could, technically, call 458*24edb884SFrançois Tigeot * iget() + drm_fs_inode_free() directly after alloc and sometime later do an 459*24edb884SFrançois Tigeot * iput(), but this way you'd end up with a new vfsmount for each inode. 460*24edb884SFrançois Tigeot */ 461*24edb884SFrançois Tigeot 462*24edb884SFrançois Tigeot static int drm_fs_cnt; 463*24edb884SFrançois Tigeot static struct vfsmount *drm_fs_mnt; 464*24edb884SFrançois Tigeot 465*24edb884SFrançois Tigeot static const struct dentry_operations drm_fs_dops = { 466*24edb884SFrançois Tigeot .d_dname = simple_dname, 467*24edb884SFrançois Tigeot }; 468*24edb884SFrançois Tigeot 469*24edb884SFrançois Tigeot static const struct super_operations drm_fs_sops = { 470*24edb884SFrançois Tigeot .statfs = simple_statfs, 471*24edb884SFrançois Tigeot }; 472*24edb884SFrançois Tigeot 473*24edb884SFrançois Tigeot static struct dentry *drm_fs_mount(struct file_system_type *fs_type, int flags, 474*24edb884SFrançois Tigeot const char *dev_name, void *data) 475*24edb884SFrançois Tigeot { 476*24edb884SFrançois Tigeot return mount_pseudo(fs_type, 477*24edb884SFrançois Tigeot "drm:", 478*24edb884SFrançois Tigeot &drm_fs_sops, 479*24edb884SFrançois Tigeot &drm_fs_dops, 480*24edb884SFrançois Tigeot 0x010203ff); 481*24edb884SFrançois Tigeot } 482*24edb884SFrançois Tigeot 483*24edb884SFrançois Tigeot static struct file_system_type drm_fs_type = { 484*24edb884SFrançois Tigeot .name = "drm", 485*24edb884SFrançois Tigeot .owner = THIS_MODULE, 486*24edb884SFrançois Tigeot .mount = drm_fs_mount, 487*24edb884SFrançois Tigeot .kill_sb = kill_anon_super, 488*24edb884SFrançois Tigeot }; 489*24edb884SFrançois Tigeot 490*24edb884SFrançois Tigeot static struct inode *drm_fs_inode_new(void) 491*24edb884SFrançois Tigeot { 492*24edb884SFrançois Tigeot struct inode *inode; 493*24edb884SFrançois Tigeot int r; 494*24edb884SFrançois Tigeot 495*24edb884SFrançois Tigeot r = simple_pin_fs(&drm_fs_type, &drm_fs_mnt, &drm_fs_cnt); 496*24edb884SFrançois Tigeot if (r < 0) { 497*24edb884SFrançois Tigeot DRM_ERROR("Cannot mount pseudo fs: %d\n", r); 498*24edb884SFrançois Tigeot return ERR_PTR(r); 499*24edb884SFrançois Tigeot } 500*24edb884SFrançois Tigeot 501*24edb884SFrançois Tigeot inode = alloc_anon_inode(drm_fs_mnt->mnt_sb); 502*24edb884SFrançois Tigeot if (IS_ERR(inode)) 503*24edb884SFrançois Tigeot simple_release_fs(&drm_fs_mnt, &drm_fs_cnt); 504*24edb884SFrançois Tigeot 505*24edb884SFrançois Tigeot return inode; 506*24edb884SFrançois Tigeot } 507*24edb884SFrançois Tigeot 508*24edb884SFrançois Tigeot static void drm_fs_inode_free(struct inode *inode) 509*24edb884SFrançois Tigeot { 510*24edb884SFrançois Tigeot if (inode) { 511*24edb884SFrançois Tigeot iput(inode); 512*24edb884SFrançois Tigeot simple_release_fs(&drm_fs_mnt, &drm_fs_cnt); 513*24edb884SFrançois Tigeot } 514*24edb884SFrançois Tigeot } 515*24edb884SFrançois Tigeot 516*24edb884SFrançois Tigeot /** 517*24edb884SFrançois Tigeot * drm_dev_alloc - Allocate new DRM device 518*24edb884SFrançois Tigeot * @driver: DRM driver to allocate device for 519*24edb884SFrançois Tigeot * @parent: Parent device object 520*24edb884SFrançois Tigeot * 521*24edb884SFrançois Tigeot * Allocate and initialize a new DRM device. No device registration is done. 522*24edb884SFrançois Tigeot * Call drm_dev_register() to advertice the device to user space and register it 523*24edb884SFrançois Tigeot * with other core subsystems. 524*24edb884SFrançois Tigeot * 525*24edb884SFrançois Tigeot * The initial ref-count of the object is 1. Use drm_dev_ref() and 526*24edb884SFrançois Tigeot * drm_dev_unref() to take and drop further ref-counts. 527*24edb884SFrançois Tigeot * 528*24edb884SFrançois Tigeot * RETURNS: 529*24edb884SFrançois Tigeot * Pointer to new DRM device, or NULL if out of memory. 530*24edb884SFrançois Tigeot */ 531*24edb884SFrançois Tigeot struct drm_device *drm_dev_alloc(struct drm_driver *driver, 532*24edb884SFrançois Tigeot struct device *parent) 533*24edb884SFrançois Tigeot { 534*24edb884SFrançois Tigeot struct drm_device *dev; 535*24edb884SFrançois Tigeot int ret; 536*24edb884SFrançois Tigeot 537*24edb884SFrançois Tigeot dev = kzalloc(sizeof(*dev), GFP_KERNEL); 538*24edb884SFrançois Tigeot if (!dev) 539*24edb884SFrançois Tigeot return NULL; 540*24edb884SFrançois Tigeot 541*24edb884SFrançois Tigeot kref_init(&dev->ref); 542*24edb884SFrançois Tigeot dev->dev = parent; 543*24edb884SFrançois Tigeot dev->driver = driver; 544*24edb884SFrançois Tigeot 545*24edb884SFrançois Tigeot INIT_LIST_HEAD(&dev->filelist); 546*24edb884SFrançois Tigeot INIT_LIST_HEAD(&dev->ctxlist); 547*24edb884SFrançois Tigeot INIT_LIST_HEAD(&dev->vmalist); 548*24edb884SFrançois Tigeot INIT_LIST_HEAD(&dev->maplist); 549*24edb884SFrançois Tigeot INIT_LIST_HEAD(&dev->vblank_event_list); 550*24edb884SFrançois Tigeot 551*24edb884SFrançois Tigeot spin_lock_init(&dev->buf_lock); 552*24edb884SFrançois Tigeot spin_lock_init(&dev->event_lock); 553*24edb884SFrançois Tigeot mutex_init(&dev->struct_mutex); 554*24edb884SFrançois Tigeot mutex_init(&dev->ctxlist_mutex); 555*24edb884SFrançois Tigeot mutex_init(&dev->master_mutex); 556*24edb884SFrançois Tigeot 557*24edb884SFrançois Tigeot dev->anon_inode = drm_fs_inode_new(); 558*24edb884SFrançois Tigeot if (IS_ERR(dev->anon_inode)) { 559*24edb884SFrançois Tigeot ret = PTR_ERR(dev->anon_inode); 560*24edb884SFrançois Tigeot DRM_ERROR("Cannot allocate anonymous inode: %d\n", ret); 561*24edb884SFrançois Tigeot goto err_free; 562*24edb884SFrançois Tigeot } 563*24edb884SFrançois Tigeot 564*24edb884SFrançois Tigeot if (drm_core_check_feature(dev, DRIVER_MODESET)) { 565*24edb884SFrançois Tigeot ret = drm_minor_alloc(dev, DRM_MINOR_CONTROL); 566*24edb884SFrançois Tigeot if (ret) 567*24edb884SFrançois Tigeot goto err_minors; 568*24edb884SFrançois Tigeot } 569*24edb884SFrançois Tigeot 570*24edb884SFrançois Tigeot if (drm_core_check_feature(dev, DRIVER_RENDER)) { 571*24edb884SFrançois Tigeot ret = drm_minor_alloc(dev, DRM_MINOR_RENDER); 572*24edb884SFrançois Tigeot if (ret) 573*24edb884SFrançois Tigeot goto err_minors; 574*24edb884SFrançois Tigeot } 575*24edb884SFrançois Tigeot 576*24edb884SFrançois Tigeot ret = drm_minor_alloc(dev, DRM_MINOR_LEGACY); 577*24edb884SFrançois Tigeot if (ret) 578*24edb884SFrançois Tigeot goto err_minors; 579*24edb884SFrançois Tigeot 580*24edb884SFrançois Tigeot if (drm_ht_create(&dev->map_hash, 12)) 581*24edb884SFrançois Tigeot goto err_minors; 582*24edb884SFrançois Tigeot 583*24edb884SFrançois Tigeot ret = drm_legacy_ctxbitmap_init(dev); 584*24edb884SFrançois Tigeot if (ret) { 585*24edb884SFrançois Tigeot DRM_ERROR("Cannot allocate memory for context bitmap.\n"); 586*24edb884SFrançois Tigeot goto err_ht; 587*24edb884SFrançois Tigeot } 588*24edb884SFrançois Tigeot 589*24edb884SFrançois Tigeot if (driver->driver_features & DRIVER_GEM) { 590*24edb884SFrançois Tigeot ret = drm_gem_init(dev); 591*24edb884SFrançois Tigeot if (ret) { 592*24edb884SFrançois Tigeot DRM_ERROR("Cannot initialize graphics execution manager (GEM)\n"); 593*24edb884SFrançois Tigeot goto err_ctxbitmap; 594*24edb884SFrançois Tigeot } 595*24edb884SFrançois Tigeot } 596*24edb884SFrançois Tigeot 597*24edb884SFrançois Tigeot return dev; 598*24edb884SFrançois Tigeot 599*24edb884SFrançois Tigeot err_ctxbitmap: 600*24edb884SFrançois Tigeot drm_legacy_ctxbitmap_cleanup(dev); 601*24edb884SFrançois Tigeot err_ht: 602*24edb884SFrançois Tigeot drm_ht_remove(&dev->map_hash); 603*24edb884SFrançois Tigeot err_minors: 604*24edb884SFrançois Tigeot drm_minor_free(dev, DRM_MINOR_LEGACY); 605*24edb884SFrançois Tigeot drm_minor_free(dev, DRM_MINOR_RENDER); 606*24edb884SFrançois Tigeot drm_minor_free(dev, DRM_MINOR_CONTROL); 607*24edb884SFrançois Tigeot drm_fs_inode_free(dev->anon_inode); 608*24edb884SFrançois Tigeot err_free: 609*24edb884SFrançois Tigeot mutex_destroy(&dev->master_mutex); 610*24edb884SFrançois Tigeot kfree(dev); 611*24edb884SFrançois Tigeot return NULL; 612*24edb884SFrançois Tigeot } 613*24edb884SFrançois Tigeot EXPORT_SYMBOL(drm_dev_alloc); 614*24edb884SFrançois Tigeot 615*24edb884SFrançois Tigeot static void drm_dev_release(struct kref *ref) 616*24edb884SFrançois Tigeot { 617*24edb884SFrançois Tigeot struct drm_device *dev = container_of(ref, struct drm_device, ref); 618*24edb884SFrançois Tigeot 619*24edb884SFrançois Tigeot if (dev->driver->driver_features & DRIVER_GEM) 620*24edb884SFrançois Tigeot drm_gem_destroy(dev); 621*24edb884SFrançois Tigeot 622*24edb884SFrançois Tigeot drm_legacy_ctxbitmap_cleanup(dev); 623*24edb884SFrançois Tigeot drm_ht_remove(&dev->map_hash); 624*24edb884SFrançois Tigeot drm_fs_inode_free(dev->anon_inode); 625*24edb884SFrançois Tigeot 626*24edb884SFrançois Tigeot drm_minor_free(dev, DRM_MINOR_LEGACY); 627*24edb884SFrançois Tigeot drm_minor_free(dev, DRM_MINOR_RENDER); 628*24edb884SFrançois Tigeot drm_minor_free(dev, DRM_MINOR_CONTROL); 629*24edb884SFrançois Tigeot 630*24edb884SFrançois Tigeot mutex_destroy(&dev->master_mutex); 631*24edb884SFrançois Tigeot kfree(dev->unique); 632*24edb884SFrançois Tigeot kfree(dev); 633*24edb884SFrançois Tigeot } 634*24edb884SFrançois Tigeot 635*24edb884SFrançois Tigeot /** 636*24edb884SFrançois Tigeot * drm_dev_ref - Take reference of a DRM device 637*24edb884SFrançois Tigeot * @dev: device to take reference of or NULL 638*24edb884SFrançois Tigeot * 639*24edb884SFrançois Tigeot * This increases the ref-count of @dev by one. You *must* already own a 640*24edb884SFrançois Tigeot * reference when calling this. Use drm_dev_unref() to drop this reference 641*24edb884SFrançois Tigeot * again. 642*24edb884SFrançois Tigeot * 643*24edb884SFrançois Tigeot * This function never fails. However, this function does not provide *any* 644*24edb884SFrançois Tigeot * guarantee whether the device is alive or running. It only provides a 645*24edb884SFrançois Tigeot * reference to the object and the memory associated with it. 646*24edb884SFrançois Tigeot */ 647*24edb884SFrançois Tigeot void drm_dev_ref(struct drm_device *dev) 648*24edb884SFrançois Tigeot { 649*24edb884SFrançois Tigeot if (dev) 650*24edb884SFrançois Tigeot kref_get(&dev->ref); 651*24edb884SFrançois Tigeot } 652*24edb884SFrançois Tigeot EXPORT_SYMBOL(drm_dev_ref); 653*24edb884SFrançois Tigeot 654*24edb884SFrançois Tigeot /** 655*24edb884SFrançois Tigeot * drm_dev_unref - Drop reference of a DRM device 656*24edb884SFrançois Tigeot * @dev: device to drop reference of or NULL 657*24edb884SFrançois Tigeot * 658*24edb884SFrançois Tigeot * This decreases the ref-count of @dev by one. The device is destroyed if the 659*24edb884SFrançois Tigeot * ref-count drops to zero. 660*24edb884SFrançois Tigeot */ 661*24edb884SFrançois Tigeot void drm_dev_unref(struct drm_device *dev) 662*24edb884SFrançois Tigeot { 663*24edb884SFrançois Tigeot if (dev) 664*24edb884SFrançois Tigeot kref_put(&dev->ref, drm_dev_release); 665*24edb884SFrançois Tigeot } 666*24edb884SFrançois Tigeot EXPORT_SYMBOL(drm_dev_unref); 667*24edb884SFrançois Tigeot 668*24edb884SFrançois Tigeot /** 669*24edb884SFrançois Tigeot * drm_dev_register - Register DRM device 670*24edb884SFrançois Tigeot * @dev: Device to register 671*24edb884SFrançois Tigeot * @flags: Flags passed to the driver's .load() function 672*24edb884SFrançois Tigeot * 673*24edb884SFrançois Tigeot * Register the DRM device @dev with the system, advertise device to user-space 674*24edb884SFrançois Tigeot * and start normal device operation. @dev must be allocated via drm_dev_alloc() 675*24edb884SFrançois Tigeot * previously. 676*24edb884SFrançois Tigeot * 677*24edb884SFrançois Tigeot * Never call this twice on any device! 678*24edb884SFrançois Tigeot * 679*24edb884SFrançois Tigeot * RETURNS: 680*24edb884SFrançois Tigeot * 0 on success, negative error code on failure. 681*24edb884SFrançois Tigeot */ 682*24edb884SFrançois Tigeot int drm_dev_register(struct drm_device *dev, unsigned long flags) 683*24edb884SFrançois Tigeot { 684*24edb884SFrançois Tigeot int ret; 685*24edb884SFrançois Tigeot 686*24edb884SFrançois Tigeot mutex_lock(&drm_global_mutex); 687*24edb884SFrançois Tigeot 688*24edb884SFrançois Tigeot ret = drm_minor_register(dev, DRM_MINOR_CONTROL); 689*24edb884SFrançois Tigeot if (ret) 690*24edb884SFrançois Tigeot goto err_minors; 691*24edb884SFrançois Tigeot 692*24edb884SFrançois Tigeot ret = drm_minor_register(dev, DRM_MINOR_RENDER); 693*24edb884SFrançois Tigeot if (ret) 694*24edb884SFrançois Tigeot goto err_minors; 695*24edb884SFrançois Tigeot 696*24edb884SFrançois Tigeot ret = drm_minor_register(dev, DRM_MINOR_LEGACY); 697*24edb884SFrançois Tigeot if (ret) 698*24edb884SFrançois Tigeot goto err_minors; 699*24edb884SFrançois Tigeot 700*24edb884SFrançois Tigeot if (dev->driver->load) { 701*24edb884SFrançois Tigeot ret = dev->driver->load(dev, flags); 702*24edb884SFrançois Tigeot if (ret) 703*24edb884SFrançois Tigeot goto err_minors; 704*24edb884SFrançois Tigeot } 705*24edb884SFrançois Tigeot 706*24edb884SFrançois Tigeot /* setup grouping for legacy outputs */ 707*24edb884SFrançois Tigeot if (drm_core_check_feature(dev, DRIVER_MODESET)) { 708*24edb884SFrançois Tigeot ret = drm_mode_group_init_legacy_group(dev, 709*24edb884SFrançois Tigeot &dev->primary->mode_group); 710*24edb884SFrançois Tigeot if (ret) 711*24edb884SFrançois Tigeot goto err_unload; 712*24edb884SFrançois Tigeot } 713*24edb884SFrançois Tigeot 714*24edb884SFrançois Tigeot ret = 0; 715*24edb884SFrançois Tigeot goto out_unlock; 716*24edb884SFrançois Tigeot 717*24edb884SFrançois Tigeot err_unload: 718*24edb884SFrançois Tigeot if (dev->driver->unload) 719*24edb884SFrançois Tigeot dev->driver->unload(dev); 720*24edb884SFrançois Tigeot err_minors: 721*24edb884SFrançois Tigeot drm_minor_unregister(dev, DRM_MINOR_LEGACY); 722*24edb884SFrançois Tigeot drm_minor_unregister(dev, DRM_MINOR_RENDER); 723*24edb884SFrançois Tigeot drm_minor_unregister(dev, DRM_MINOR_CONTROL); 724*24edb884SFrançois Tigeot out_unlock: 725*24edb884SFrançois Tigeot mutex_unlock(&drm_global_mutex); 726*24edb884SFrançois Tigeot return ret; 727*24edb884SFrançois Tigeot } 728*24edb884SFrançois Tigeot EXPORT_SYMBOL(drm_dev_register); 729*24edb884SFrançois Tigeot 730*24edb884SFrançois Tigeot /** 731*24edb884SFrançois Tigeot * drm_dev_unregister - Unregister DRM device 732*24edb884SFrançois Tigeot * @dev: Device to unregister 733*24edb884SFrançois Tigeot * 734*24edb884SFrançois Tigeot * Unregister the DRM device from the system. This does the reverse of 735*24edb884SFrançois Tigeot * drm_dev_register() but does not deallocate the device. The caller must call 736*24edb884SFrançois Tigeot * drm_dev_unref() to drop their final reference. 737*24edb884SFrançois Tigeot */ 738*24edb884SFrançois Tigeot void drm_dev_unregister(struct drm_device *dev) 739*24edb884SFrançois Tigeot { 740*24edb884SFrançois Tigeot struct drm_map_list *r_list, *list_temp; 741*24edb884SFrançois Tigeot 742*24edb884SFrançois Tigeot drm_lastclose(dev); 743*24edb884SFrançois Tigeot 744*24edb884SFrançois Tigeot if (dev->driver->unload) 745*24edb884SFrançois Tigeot dev->driver->unload(dev); 746*24edb884SFrançois Tigeot 747*24edb884SFrançois Tigeot if (dev->agp) 748*24edb884SFrançois Tigeot drm_pci_agp_destroy(dev); 749*24edb884SFrançois Tigeot 750*24edb884SFrançois Tigeot drm_vblank_cleanup(dev); 751*24edb884SFrançois Tigeot 752*24edb884SFrançois Tigeot list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head) 753*24edb884SFrançois Tigeot drm_rmmap(dev, r_list->map); 754*24edb884SFrançois Tigeot 755*24edb884SFrançois Tigeot drm_minor_unregister(dev, DRM_MINOR_LEGACY); 756*24edb884SFrançois Tigeot drm_minor_unregister(dev, DRM_MINOR_RENDER); 757*24edb884SFrançois Tigeot drm_minor_unregister(dev, DRM_MINOR_CONTROL); 758*24edb884SFrançois Tigeot } 759*24edb884SFrançois Tigeot EXPORT_SYMBOL(drm_dev_unregister); 760*24edb884SFrançois Tigeot 761*24edb884SFrançois Tigeot /** 762*24edb884SFrançois Tigeot * drm_dev_set_unique - Set the unique name of a DRM device 763*24edb884SFrançois Tigeot * @dev: device of which to set the unique name 764*24edb884SFrançois Tigeot * @fmt: format string for unique name 765*24edb884SFrançois Tigeot * 766*24edb884SFrançois Tigeot * Sets the unique name of a DRM device using the specified format string and 767*24edb884SFrançois Tigeot * a variable list of arguments. Drivers can use this at driver probe time if 768*24edb884SFrançois Tigeot * the unique name of the devices they drive is static. 769*24edb884SFrançois Tigeot * 770*24edb884SFrançois Tigeot * Return: 0 on success or a negative error code on failure. 771*24edb884SFrançois Tigeot */ 772*24edb884SFrançois Tigeot int drm_dev_set_unique(struct drm_device *dev, const char *fmt, ...) 773*24edb884SFrançois Tigeot { 774*24edb884SFrançois Tigeot va_list ap; 775*24edb884SFrançois Tigeot 776*24edb884SFrançois Tigeot kfree(dev->unique); 777*24edb884SFrançois Tigeot 778*24edb884SFrançois Tigeot va_start(ap, fmt); 779*24edb884SFrançois Tigeot dev->unique = kvasprintf(GFP_KERNEL, fmt, ap); 780*24edb884SFrançois Tigeot va_end(ap); 781*24edb884SFrançois Tigeot 782*24edb884SFrançois Tigeot return dev->unique ? 0 : -ENOMEM; 783*24edb884SFrançois Tigeot } 784*24edb884SFrançois Tigeot EXPORT_SYMBOL(drm_dev_set_unique); 785*24edb884SFrançois Tigeot #endif 786*24edb884SFrançois Tigeot 787*24edb884SFrançois Tigeot /* 788*24edb884SFrançois Tigeot * DRM Core 789*24edb884SFrançois Tigeot * The DRM core module initializes all global DRM objects and makes them 790*24edb884SFrançois Tigeot * available to drivers. Once setup, drivers can probe their respective 791*24edb884SFrançois Tigeot * devices. 792*24edb884SFrançois Tigeot * Currently, core management includes: 793*24edb884SFrançois Tigeot * - The "DRM-Global" key/value database 794*24edb884SFrançois Tigeot * - Global ID management for connectors 795*24edb884SFrançois Tigeot * - DRM major number allocation 796*24edb884SFrançois Tigeot * - DRM minor management 797*24edb884SFrançois Tigeot * - DRM sysfs class 798*24edb884SFrançois Tigeot * - DRM debugfs root 799*24edb884SFrançois Tigeot * 800*24edb884SFrançois Tigeot * Furthermore, the DRM core provides dynamic char-dev lookups. For each 801*24edb884SFrançois Tigeot * interface registered on a DRM device, you can request minor numbers from DRM 802*24edb884SFrançois Tigeot * core. DRM core takes care of major-number management and char-dev 803*24edb884SFrançois Tigeot * registration. A stub ->open() callback forwards any open() requests to the 804*24edb884SFrançois Tigeot * registered minor. 805*24edb884SFrançois Tigeot */ 806*24edb884SFrançois Tigeot 807*24edb884SFrançois Tigeot #if 0 808*24edb884SFrançois Tigeot static int drm_stub_open(struct inode *inode, struct file *filp) 809*24edb884SFrançois Tigeot { 810*24edb884SFrançois Tigeot const struct file_operations *new_fops; 811*24edb884SFrançois Tigeot struct drm_minor *minor; 812*24edb884SFrançois Tigeot int err; 813*24edb884SFrançois Tigeot 814*24edb884SFrançois Tigeot DRM_DEBUG("\n"); 815*24edb884SFrançois Tigeot 816*24edb884SFrançois Tigeot mutex_lock(&drm_global_mutex); 817*24edb884SFrançois Tigeot minor = drm_minor_acquire(iminor(inode)); 818*24edb884SFrançois Tigeot if (IS_ERR(minor)) { 819*24edb884SFrançois Tigeot err = PTR_ERR(minor); 820*24edb884SFrançois Tigeot goto out_unlock; 821*24edb884SFrançois Tigeot } 822*24edb884SFrançois Tigeot 823*24edb884SFrançois Tigeot new_fops = fops_get(minor->dev->driver->fops); 824*24edb884SFrançois Tigeot if (!new_fops) { 825*24edb884SFrançois Tigeot err = -ENODEV; 826*24edb884SFrançois Tigeot goto out_release; 827*24edb884SFrançois Tigeot } 828*24edb884SFrançois Tigeot 829*24edb884SFrançois Tigeot replace_fops(filp, new_fops); 830*24edb884SFrançois Tigeot if (filp->f_op->open) 831*24edb884SFrançois Tigeot err = filp->f_op->open(inode, filp); 832*24edb884SFrançois Tigeot else 833*24edb884SFrançois Tigeot err = 0; 834*24edb884SFrançois Tigeot 835*24edb884SFrançois Tigeot out_release: 836*24edb884SFrançois Tigeot drm_minor_release(minor); 837*24edb884SFrançois Tigeot out_unlock: 838*24edb884SFrançois Tigeot mutex_unlock(&drm_global_mutex); 839*24edb884SFrançois Tigeot return err; 840*24edb884SFrançois Tigeot } 841*24edb884SFrançois Tigeot 842*24edb884SFrançois Tigeot static const struct file_operations drm_stub_fops = { 843*24edb884SFrançois Tigeot .owner = THIS_MODULE, 844*24edb884SFrançois Tigeot .open = drm_stub_open, 845*24edb884SFrançois Tigeot .llseek = noop_llseek, 846*24edb884SFrançois Tigeot }; 847*24edb884SFrançois Tigeot 848*24edb884SFrançois Tigeot static int __init drm_core_init(void) 849*24edb884SFrançois Tigeot { 850*24edb884SFrançois Tigeot int ret = -ENOMEM; 851*24edb884SFrançois Tigeot 852*24edb884SFrançois Tigeot drm_global_init(); 853*24edb884SFrançois Tigeot drm_connector_ida_init(); 854*24edb884SFrançois Tigeot idr_init(&drm_minors_idr); 855*24edb884SFrançois Tigeot 856*24edb884SFrançois Tigeot if (register_chrdev(DRM_MAJOR, "drm", &drm_stub_fops)) 857*24edb884SFrançois Tigeot goto err_p1; 858*24edb884SFrançois Tigeot 859*24edb884SFrançois Tigeot drm_class = drm_sysfs_create(THIS_MODULE, "drm"); 860*24edb884SFrançois Tigeot if (IS_ERR(drm_class)) { 861*24edb884SFrançois Tigeot printk(KERN_ERR "DRM: Error creating drm class.\n"); 862*24edb884SFrançois Tigeot ret = PTR_ERR(drm_class); 863*24edb884SFrançois Tigeot goto err_p2; 864*24edb884SFrançois Tigeot } 865*24edb884SFrançois Tigeot 866*24edb884SFrançois Tigeot drm_debugfs_root = debugfs_create_dir("dri", NULL); 867*24edb884SFrançois Tigeot if (!drm_debugfs_root) { 868*24edb884SFrançois Tigeot DRM_ERROR("Cannot create /sys/kernel/debug/dri\n"); 869*24edb884SFrançois Tigeot ret = -1; 870*24edb884SFrançois Tigeot goto err_p3; 871*24edb884SFrançois Tigeot } 872*24edb884SFrançois Tigeot 873*24edb884SFrançois Tigeot DRM_INFO("Initialized %s %d.%d.%d %s\n", 874*24edb884SFrançois Tigeot CORE_NAME, CORE_MAJOR, CORE_MINOR, CORE_PATCHLEVEL, CORE_DATE); 875*24edb884SFrançois Tigeot return 0; 876*24edb884SFrançois Tigeot err_p3: 877*24edb884SFrançois Tigeot drm_sysfs_destroy(); 878*24edb884SFrançois Tigeot err_p2: 879*24edb884SFrançois Tigeot unregister_chrdev(DRM_MAJOR, "drm"); 880*24edb884SFrançois Tigeot 881*24edb884SFrançois Tigeot idr_destroy(&drm_minors_idr); 882*24edb884SFrançois Tigeot err_p1: 883*24edb884SFrançois Tigeot return ret; 884*24edb884SFrançois Tigeot } 885*24edb884SFrançois Tigeot 886*24edb884SFrançois Tigeot static void __exit drm_core_exit(void) 887*24edb884SFrançois Tigeot { 888*24edb884SFrançois Tigeot debugfs_remove(drm_debugfs_root); 889*24edb884SFrançois Tigeot drm_sysfs_destroy(); 890*24edb884SFrançois Tigeot 891*24edb884SFrançois Tigeot unregister_chrdev(DRM_MAJOR, "drm"); 892*24edb884SFrançois Tigeot 893*24edb884SFrançois Tigeot drm_connector_ida_destroy(); 894*24edb884SFrançois Tigeot idr_destroy(&drm_minors_idr); 895*24edb884SFrançois Tigeot } 896*24edb884SFrançois Tigeot 897*24edb884SFrançois Tigeot module_init(drm_core_init); 898*24edb884SFrançois Tigeot module_exit(drm_core_exit); 899*24edb884SFrançois Tigeot #endif 900*24edb884SFrançois Tigeot 90179f713b0SFrançois Tigeot #include <sys/devfs.h> 9025718399fSFrançois Tigeot 9039edbd4a0SFrançois Tigeot #include <linux/export.h> 904be348e9fSFrançois Tigeot #include <linux/dmi.h> 90518e26a6dSFrançois Tigeot #include <drm/drmP.h> 90618e26a6dSFrançois Tigeot #include <drm/drm_core.h> 9077f3c3d6fSHasso Tepper 90864fe1516Szrj #if DRM_DEBUG_DEFAULT_ON == 1 90964fe1516Szrj #define DRM_DEBUGBITS_ON (DRM_DEBUGBITS_DEBUG | DRM_DEBUGBITS_KMS | \ 91064fe1516Szrj DRM_DEBUGBITS_FAILED_IOCTL) 91164fe1516Szrj #elif DRM_DEBUG_DEFAULT_ON == 2 91264fe1516Szrj #define DRM_DEBUGBITS_ON (DRM_DEBUGBITS_DEBUG | DRM_DEBUGBITS_KMS | \ 91364fe1516Szrj DRM_DEBUGBITS_FAILED_IOCTL | DRM_DEBUGBITS_VERBOSE) 91479f713b0SFrançois Tigeot #else 91564fe1516Szrj #define DRM_DEBUGBITS_ON (0x0) 91679f713b0SFrançois Tigeot #endif 91764fe1516Szrj 9185718399fSFrançois Tigeot int drm_notyet_flag = 0; 9195718399fSFrançois Tigeot 920b3705d71SHasso Tepper static int drm_load(struct drm_device *dev); 9213260c067SFrançois Tigeot drm_pci_id_list_t *drm_find_description(int vendor, int device, 9227f3c3d6fSHasso Tepper drm_pci_id_list_t *idlist); 9237f3c3d6fSHasso Tepper 9247f3c3d6fSHasso Tepper #define DRIVER_SOFTC(unit) \ 925b3705d71SHasso Tepper ((struct drm_device *)devclass_get_softc(drm_devclass, unit)) 9267f3c3d6fSHasso Tepper 9275718399fSFrançois Tigeot static int 9285718399fSFrançois Tigeot drm_modevent(module_t mod, int type, void *data) 9295718399fSFrançois Tigeot { 9305718399fSFrançois Tigeot 9315718399fSFrançois Tigeot switch (type) { 9325718399fSFrançois Tigeot case MOD_LOAD: 9331d5dd71dSFrançois Tigeot TUNABLE_INT_FETCH("drm.debug", &drm_debug); 9345718399fSFrançois Tigeot TUNABLE_INT_FETCH("drm.notyet", &drm_notyet_flag); 9355718399fSFrançois Tigeot break; 9365718399fSFrançois Tigeot } 9375718399fSFrançois Tigeot return (0); 9385718399fSFrançois Tigeot } 9395718399fSFrançois Tigeot 9405718399fSFrançois Tigeot static moduledata_t drm_mod = { 9415718399fSFrançois Tigeot "drm", 9425718399fSFrançois Tigeot drm_modevent, 9435718399fSFrançois Tigeot 0 9445718399fSFrançois Tigeot }; 9455718399fSFrançois Tigeot DECLARE_MODULE(drm, drm_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); 9467f3c3d6fSHasso Tepper MODULE_VERSION(drm, 1); 9477f3c3d6fSHasso Tepper MODULE_DEPEND(drm, agp, 1, 1, 1); 9487f3c3d6fSHasso Tepper MODULE_DEPEND(drm, pci, 1, 1, 1); 9495718399fSFrançois Tigeot MODULE_DEPEND(drm, iicbus, 1, 1, 1); 9507f3c3d6fSHasso Tepper 95179f713b0SFrançois Tigeot static struct dev_ops drm_cdevsw = { 952d268c872SFrançois Tigeot { "drm", 0, D_TRACKCLOSE | D_MPSAFE }, 9537f3c3d6fSHasso Tepper .d_open = drm_open, 9542c845b81SSimon Schubert .d_close = drm_close, 9557f3c3d6fSHasso Tepper .d_read = drm_read, 9567f3c3d6fSHasso Tepper .d_ioctl = drm_ioctl, 9573694ee49SSamuel J. Greear .d_kqfilter = drm_kqfilter, 9585718399fSFrançois Tigeot .d_mmap = drm_mmap, 9595718399fSFrançois Tigeot .d_mmap_single = drm_mmap_single, 9607f3c3d6fSHasso Tepper }; 9617f3c3d6fSHasso Tepper 9624705af8fSMarkus Pfeiffer static int drm_msi = 0; /* Disable by default. This is because there are issues with 9634705af8fSMarkus Pfeiffer freezes using MSI and i915 9644705af8fSMarkus Pfeiffer */ 9654705af8fSMarkus Pfeiffer TUNABLE_INT("hw.drm.msi.enable", &drm_msi); 9665718399fSFrançois Tigeot SYSCTL_NODE(_hw, OID_AUTO, drm, CTLFLAG_RW, NULL, "DRM device"); 9674705af8fSMarkus Pfeiffer SYSCTL_NODE(_hw_drm, OID_AUTO, msi, CTLFLAG_RW, NULL, "DRM device msi"); 9684705af8fSMarkus Pfeiffer SYSCTL_INT(_hw_drm_msi, OID_AUTO, enable, CTLFLAG_RD, &drm_msi, 0, 9695718399fSFrançois Tigeot "Enable MSI interrupts for drm devices"); 97027a0f882SMatthew Dillon SYSCTL_INT(_hw_drm, OID_AUTO, debug, CTLFLAG_RW, &drm_debug, 0, 97127a0f882SMatthew Dillon "DRM debugging"); 972b3705d71SHasso Tepper 973b3705d71SHasso Tepper static struct drm_msi_blacklist_entry drm_msi_blacklist[] = { 974b3705d71SHasso Tepper {0x8086, 0x2772}, /* Intel i945G */ \ 975b3705d71SHasso Tepper {0x8086, 0x27A2}, /* Intel i945GM */ \ 976b3705d71SHasso Tepper {0x8086, 0x27AE}, /* Intel i945GME */ \ 977b3705d71SHasso Tepper {0, 0} 978b3705d71SHasso Tepper }; 979b3705d71SHasso Tepper 9806f486c69SFrançois Tigeot static int drm_msi_is_blacklisted(struct drm_device *dev, unsigned long flags) 981b3705d71SHasso Tepper { 982b3705d71SHasso Tepper int i = 0; 983b3705d71SHasso Tepper 9846f486c69SFrançois Tigeot if (dev->driver->use_msi != NULL) { 9856f486c69SFrançois Tigeot int use_msi; 9866f486c69SFrançois Tigeot 9876f486c69SFrançois Tigeot use_msi = dev->driver->use_msi(dev, flags); 9886f486c69SFrançois Tigeot 9896f486c69SFrançois Tigeot return (!use_msi); 9906f486c69SFrançois Tigeot } 9916f486c69SFrançois Tigeot 9926f486c69SFrançois Tigeot /* TODO: Maybe move this to a callback in i915? */ 993b3705d71SHasso Tepper for (i = 0; drm_msi_blacklist[i].vendor != 0; i++) { 9946f486c69SFrançois Tigeot if ((drm_msi_blacklist[i].vendor == dev->pci_vendor) && 9956f486c69SFrançois Tigeot (drm_msi_blacklist[i].device == dev->pci_device)) { 996b3705d71SHasso Tepper return 1; 997b3705d71SHasso Tepper } 998b3705d71SHasso Tepper } 999b3705d71SHasso Tepper 1000b3705d71SHasso Tepper return 0; 1001b3705d71SHasso Tepper } 1002b3705d71SHasso Tepper 1003b3705d71SHasso Tepper int drm_probe(device_t kdev, drm_pci_id_list_t *idlist) 10047f3c3d6fSHasso Tepper { 10057f3c3d6fSHasso Tepper drm_pci_id_list_t *id_entry; 10067f3c3d6fSHasso Tepper int vendor, device; 10077f3c3d6fSHasso Tepper 100831935f45SSepherosa Ziehau vendor = pci_get_vendor(kdev); 100931935f45SSepherosa Ziehau device = pci_get_device(kdev); 1010b3705d71SHasso Tepper 10115718399fSFrançois Tigeot if (pci_get_class(kdev) != PCIC_DISPLAY) 1012b3705d71SHasso Tepper return ENXIO; 10137f3c3d6fSHasso Tepper 10147f3c3d6fSHasso Tepper id_entry = drm_find_description(vendor, device, idlist); 10157f3c3d6fSHasso Tepper if (id_entry != NULL) { 1016b3705d71SHasso Tepper if (!device_get_desc(kdev)) { 1017b3705d71SHasso Tepper DRM_DEBUG("desc : %s\n", device_get_desc(kdev)); 1018b3705d71SHasso Tepper device_set_desc(kdev, id_entry->name); 1019b3705d71SHasso Tepper } 10207f3c3d6fSHasso Tepper return 0; 10217f3c3d6fSHasso Tepper } 10227f3c3d6fSHasso Tepper 10237f3c3d6fSHasso Tepper return ENXIO; 10247f3c3d6fSHasso Tepper } 10257f3c3d6fSHasso Tepper 1026b3705d71SHasso Tepper int drm_attach(device_t kdev, drm_pci_id_list_t *idlist) 10277f3c3d6fSHasso Tepper { 1028b3705d71SHasso Tepper struct drm_device *dev; 10297f3c3d6fSHasso Tepper drm_pci_id_list_t *id_entry; 10304705af8fSMarkus Pfeiffer int unit, error; 10314705af8fSMarkus Pfeiffer u_int irq_flags; 10324705af8fSMarkus Pfeiffer int msi_enable; 10337f3c3d6fSHasso Tepper 1034b3705d71SHasso Tepper unit = device_get_unit(kdev); 1035b3705d71SHasso Tepper dev = device_get_softc(kdev); 10367f3c3d6fSHasso Tepper 1037b3705d71SHasso Tepper if (!strcmp(device_get_name(kdev), "drmsub")) 10386df74fa7SFrançois Tigeot dev->dev = device_get_parent(kdev); 10397f3c3d6fSHasso Tepper else 10406df74fa7SFrançois Tigeot dev->dev = kdev; 1041b3705d71SHasso Tepper 10426df74fa7SFrançois Tigeot dev->pci_domain = pci_get_domain(dev->dev); 10436df74fa7SFrançois Tigeot dev->pci_bus = pci_get_bus(dev->dev); 10446df74fa7SFrançois Tigeot dev->pci_slot = pci_get_slot(dev->dev); 10456df74fa7SFrançois Tigeot dev->pci_func = pci_get_function(dev->dev); 1046b3705d71SHasso Tepper 10476df74fa7SFrançois Tigeot dev->pci_vendor = pci_get_vendor(dev->dev); 10486df74fa7SFrançois Tigeot dev->pci_device = pci_get_device(dev->dev); 10496df74fa7SFrançois Tigeot dev->pci_subvendor = pci_get_subvendor(dev->dev); 10506df74fa7SFrançois Tigeot dev->pci_subdevice = pci_get_subdevice(dev->dev); 10516f486c69SFrançois Tigeot 10526f486c69SFrançois Tigeot id_entry = drm_find_description(dev->pci_vendor, 10536f486c69SFrançois Tigeot dev->pci_device, idlist); 10546f486c69SFrançois Tigeot dev->id_entry = id_entry; 1055b3705d71SHasso Tepper 1056bd121a8bSHasso Tepper if (drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) { 10574705af8fSMarkus Pfeiffer msi_enable = drm_msi; 1058b3705d71SHasso Tepper 10594705af8fSMarkus Pfeiffer if (drm_msi_is_blacklisted(dev, dev->id_entry->driver_private)) { 10604705af8fSMarkus Pfeiffer msi_enable = 0; 1061b3705d71SHasso Tepper } 10624705af8fSMarkus Pfeiffer 10634705af8fSMarkus Pfeiffer dev->irq_type = pci_alloc_1intr(dev->dev, msi_enable, 10644705af8fSMarkus Pfeiffer &dev->irqrid, &irq_flags); 1065b3705d71SHasso Tepper 10666df74fa7SFrançois Tigeot dev->irqr = bus_alloc_resource_any(dev->dev, SYS_RES_IRQ, 10674705af8fSMarkus Pfeiffer &dev->irqrid, irq_flags); 10684705af8fSMarkus Pfeiffer 1069b3705d71SHasso Tepper if (!dev->irqr) { 10705718399fSFrançois Tigeot return (ENOENT); 1071b3705d71SHasso Tepper } 1072b3705d71SHasso Tepper 1073b3705d71SHasso Tepper dev->irq = (int) rman_get_start(dev->irqr); 1074bd121a8bSHasso Tepper } 1075b3705d71SHasso Tepper 10765718399fSFrançois Tigeot lockinit(&dev->dev_lock, "drmdev", 0, LK_CANRECURSE); 1077b3705d71SHasso Tepper lwkt_serialize_init(&dev->irq_lock); 10785718399fSFrançois Tigeot lockinit(&dev->event_lock, "drmev", 0, LK_CANRECURSE); 1079a2fdbec6SFrançois Tigeot lockinit(&dev->struct_mutex, "drmslk", 0, LK_CANRECURSE); 1080b3705d71SHasso Tepper 10816f486c69SFrançois Tigeot error = drm_load(dev); 10826f486c69SFrançois Tigeot if (error) 10836f486c69SFrançois Tigeot goto error; 10847f3c3d6fSHasso Tepper 108579f713b0SFrançois Tigeot error = drm_create_cdevs(kdev); 108679f713b0SFrançois Tigeot if (error) 108779f713b0SFrançois Tigeot goto error; 108879f713b0SFrançois Tigeot 10896f486c69SFrançois Tigeot return (error); 10906f486c69SFrançois Tigeot error: 10916f486c69SFrançois Tigeot if (dev->irqr) { 10926df74fa7SFrançois Tigeot bus_release_resource(dev->dev, SYS_RES_IRQ, 10936f486c69SFrançois Tigeot dev->irqrid, dev->irqr); 10946f486c69SFrançois Tigeot } 10954705af8fSMarkus Pfeiffer if (dev->irq_type == PCI_INTR_TYPE_MSI) { 10966df74fa7SFrançois Tigeot pci_release_msi(dev->dev); 10976f486c69SFrançois Tigeot } 10986f486c69SFrançois Tigeot return (error); 10996f486c69SFrançois Tigeot } 11006f486c69SFrançois Tigeot 110179f713b0SFrançois Tigeot int 110279f713b0SFrançois Tigeot drm_create_cdevs(device_t kdev) 110379f713b0SFrançois Tigeot { 110479f713b0SFrançois Tigeot struct drm_device *dev; 110579f713b0SFrançois Tigeot int error, unit; 110679f713b0SFrançois Tigeot 110779f713b0SFrançois Tigeot unit = device_get_unit(kdev); 110879f713b0SFrançois Tigeot dev = device_get_softc(kdev); 110979f713b0SFrançois Tigeot 111079f713b0SFrançois Tigeot dev->devnode = make_dev(&drm_cdevsw, unit, DRM_DEV_UID, DRM_DEV_GID, 111179f713b0SFrançois Tigeot DRM_DEV_MODE, "dri/card%d", unit); 111279f713b0SFrançois Tigeot error = 0; 111379f713b0SFrançois Tigeot if (error == 0) 111479f713b0SFrançois Tigeot dev->devnode->si_drv1 = dev; 111579f713b0SFrançois Tigeot return (error); 111679f713b0SFrançois Tigeot } 111779f713b0SFrançois Tigeot 11187f3c3d6fSHasso Tepper #ifndef DRM_DEV_NAME 11197f3c3d6fSHasso Tepper #define DRM_DEV_NAME "drm" 11207f3c3d6fSHasso Tepper #endif 11217f3c3d6fSHasso Tepper 11227f3c3d6fSHasso Tepper devclass_t drm_devclass; 11237f3c3d6fSHasso Tepper 11247f3c3d6fSHasso Tepper drm_pci_id_list_t *drm_find_description(int vendor, int device, 11257f3c3d6fSHasso Tepper drm_pci_id_list_t *idlist) 11267f3c3d6fSHasso Tepper { 11277f3c3d6fSHasso Tepper int i = 0; 11287f3c3d6fSHasso Tepper 11297f3c3d6fSHasso Tepper for (i = 0; idlist[i].vendor != 0; i++) { 11307f3c3d6fSHasso Tepper if ((idlist[i].vendor == vendor) && 1131b3705d71SHasso Tepper ((idlist[i].device == device) || 1132b3705d71SHasso Tepper (idlist[i].device == 0))) { 11337f3c3d6fSHasso Tepper return &idlist[i]; 11347f3c3d6fSHasso Tepper } 11357f3c3d6fSHasso Tepper } 11367f3c3d6fSHasso Tepper return NULL; 11377f3c3d6fSHasso Tepper } 11387f3c3d6fSHasso Tepper 1139f599cd46SFrançois Tigeot /** 1140f599cd46SFrançois Tigeot * Take down the DRM device. 1141f599cd46SFrançois Tigeot * 1142f599cd46SFrançois Tigeot * \param dev DRM device structure. 1143f599cd46SFrançois Tigeot * 1144f599cd46SFrançois Tigeot * Frees every resource in \p dev. 1145f599cd46SFrançois Tigeot * 1146f599cd46SFrançois Tigeot * \sa drm_device 1147f599cd46SFrançois Tigeot */ 1148d0cc45b6SFrançois Tigeot int drm_lastclose(struct drm_device * dev) 11497f3c3d6fSHasso Tepper { 115079f713b0SFrançois Tigeot drm_magic_entry_t *pt, *next; 11517f3c3d6fSHasso Tepper 11527f3c3d6fSHasso Tepper DRM_DEBUG("\n"); 11537f3c3d6fSHasso Tepper 1154b3705d71SHasso Tepper if (dev->driver->lastclose != NULL) 1155b3705d71SHasso Tepper dev->driver->lastclose(dev); 11567f3c3d6fSHasso Tepper 115779f713b0SFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_MODESET) && dev->irq_enabled) 11587f3c3d6fSHasso Tepper drm_irq_uninstall(dev); 11597f3c3d6fSHasso Tepper 116079f713b0SFrançois Tigeot DRM_LOCK(dev); 116179f713b0SFrançois Tigeot if (dev->unique) { 116279f713b0SFrançois Tigeot drm_free(dev->unique, M_DRM); 116379f713b0SFrançois Tigeot dev->unique = NULL; 116479f713b0SFrançois Tigeot dev->unique_len = 0; 116579f713b0SFrançois Tigeot } 11669edbd4a0SFrançois Tigeot 116779f713b0SFrançois Tigeot /* Clear pid list */ 11689edbd4a0SFrançois Tigeot if (dev->magicfree.next) { 11699edbd4a0SFrançois Tigeot list_for_each_entry_safe(pt, next, &dev->magicfree, head) { 11709edbd4a0SFrançois Tigeot list_del(&pt->head); 11719edbd4a0SFrançois Tigeot drm_ht_remove_item(&dev->magiclist, &pt->hash_item); 11729edbd4a0SFrançois Tigeot kfree(pt); 117379f713b0SFrançois Tigeot } 11749edbd4a0SFrançois Tigeot drm_ht_remove(&dev->magiclist); 117579f713b0SFrançois Tigeot } 11767f3c3d6fSHasso Tepper 11777f3c3d6fSHasso Tepper /* Clear AGP information */ 11787f3c3d6fSHasso Tepper if (dev->agp) { 11797f3c3d6fSHasso Tepper drm_agp_mem_t *entry; 11807f3c3d6fSHasso Tepper drm_agp_mem_t *nexte; 11817f3c3d6fSHasso Tepper 11827f3c3d6fSHasso Tepper /* Remove AGP resources, but leave dev->agp intact until 11837f3c3d6fSHasso Tepper * drm_unload is called. 11847f3c3d6fSHasso Tepper */ 11857f3c3d6fSHasso Tepper for (entry = dev->agp->memory; entry; entry = nexte) { 11867f3c3d6fSHasso Tepper nexte = entry->next; 11877f3c3d6fSHasso Tepper if (entry->bound) 11887f3c3d6fSHasso Tepper drm_agp_unbind_memory(entry->handle); 11897f3c3d6fSHasso Tepper drm_agp_free_memory(entry->handle); 11905a3b77d5SFrançois Tigeot drm_free(entry, M_DRM); 11917f3c3d6fSHasso Tepper } 11927f3c3d6fSHasso Tepper dev->agp->memory = NULL; 11937f3c3d6fSHasso Tepper 11947f3c3d6fSHasso Tepper if (dev->agp->acquired) 11957f3c3d6fSHasso Tepper drm_agp_release(dev); 11967f3c3d6fSHasso Tepper 11977f3c3d6fSHasso Tepper dev->agp->acquired = 0; 11987f3c3d6fSHasso Tepper dev->agp->enabled = 0; 11997f3c3d6fSHasso Tepper } 12007f3c3d6fSHasso Tepper if (dev->sg != NULL) { 12017f3c3d6fSHasso Tepper drm_sg_cleanup(dev->sg); 12027f3c3d6fSHasso Tepper dev->sg = NULL; 12037f3c3d6fSHasso Tepper } 12047f3c3d6fSHasso Tepper 12057f3c3d6fSHasso Tepper drm_dma_takedown(dev); 120679f713b0SFrançois Tigeot if (dev->lock.hw_lock) { 120779f713b0SFrançois Tigeot dev->lock.hw_lock = NULL; /* SHM removed */ 120879f713b0SFrançois Tigeot dev->lock.file_priv = NULL; 1209c6f73aabSFrançois Tigeot wakeup(&dev->lock.lock_queue); 121079f713b0SFrançois Tigeot } 121179f713b0SFrançois Tigeot DRM_UNLOCK(dev); 12127f3c3d6fSHasso Tepper 12137f3c3d6fSHasso Tepper return 0; 12147f3c3d6fSHasso Tepper } 12157f3c3d6fSHasso Tepper 1216b3705d71SHasso Tepper static int drm_load(struct drm_device *dev) 12177f3c3d6fSHasso Tepper { 12187f3c3d6fSHasso Tepper int i, retcode; 12197f3c3d6fSHasso Tepper 12207f3c3d6fSHasso Tepper DRM_DEBUG("\n"); 12217f3c3d6fSHasso Tepper 1222f599cd46SFrançois Tigeot INIT_LIST_HEAD(&dev->maplist); 12237f3c3d6fSHasso Tepper 12247f3c3d6fSHasso Tepper drm_mem_init(); 12257f3c3d6fSHasso Tepper drm_sysctl_init(dev); 12261610a1a0SFrançois Tigeot INIT_LIST_HEAD(&dev->filelist); 12277f3c3d6fSHasso Tepper 12287f3c3d6fSHasso Tepper dev->counters = 6; 12297f3c3d6fSHasso Tepper dev->types[0] = _DRM_STAT_LOCK; 12307f3c3d6fSHasso Tepper dev->types[1] = _DRM_STAT_OPENS; 12317f3c3d6fSHasso Tepper dev->types[2] = _DRM_STAT_CLOSES; 12327f3c3d6fSHasso Tepper dev->types[3] = _DRM_STAT_IOCTLS; 12337f3c3d6fSHasso Tepper dev->types[4] = _DRM_STAT_LOCKS; 12347f3c3d6fSHasso Tepper dev->types[5] = _DRM_STAT_UNLOCKS; 12357f3c3d6fSHasso Tepper 1236c6f73aabSFrançois Tigeot for (i = 0; i < ARRAY_SIZE(dev->counts); i++) 12377f3c3d6fSHasso Tepper atomic_set(&dev->counts[i], 0); 12387f3c3d6fSHasso Tepper 12395718399fSFrançois Tigeot INIT_LIST_HEAD(&dev->vblank_event_list); 12407f3c3d6fSHasso Tepper 1241b3705d71SHasso Tepper if (drm_core_has_AGP(dev)) { 12427f3c3d6fSHasso Tepper if (drm_device_is_agp(dev)) 12437f3c3d6fSHasso Tepper dev->agp = drm_agp_init(); 1244b3705d71SHasso Tepper if (drm_core_check_feature(dev, DRIVER_REQUIRE_AGP) && 1245b3705d71SHasso Tepper dev->agp == NULL) { 12467f3c3d6fSHasso Tepper DRM_ERROR("Card isn't AGP, or couldn't initialize " 12477f3c3d6fSHasso Tepper "AGP.\n"); 12487f3c3d6fSHasso Tepper retcode = ENOMEM; 12497f3c3d6fSHasso Tepper goto error; 12507f3c3d6fSHasso Tepper } 12519d567857SJean-Sébastien Pédron if (dev->agp != NULL && dev->agp->agp_info.ai_aperture_base != 0) { 12529d567857SJean-Sébastien Pédron if (drm_mtrr_add(dev->agp->agp_info.ai_aperture_base, 12539d567857SJean-Sébastien Pédron dev->agp->agp_info.ai_aperture_size, DRM_MTRR_WC) == 0) 12549d567857SJean-Sébastien Pédron dev->agp->agp_mtrr = 1; 12557f3c3d6fSHasso Tepper } 12567f3c3d6fSHasso Tepper } 12577f3c3d6fSHasso Tepper 12585718399fSFrançois Tigeot if (dev->driver->driver_features & DRIVER_GEM) { 12595718399fSFrançois Tigeot retcode = drm_gem_init(dev); 12605718399fSFrançois Tigeot if (retcode != 0) { 12615718399fSFrançois Tigeot DRM_ERROR("Cannot initialize graphics execution " 12625718399fSFrançois Tigeot "manager (GEM)\n"); 12635718399fSFrançois Tigeot goto error1; 12645718399fSFrançois Tigeot } 12655718399fSFrançois Tigeot } 12665718399fSFrançois Tigeot 12675718399fSFrançois Tigeot if (dev->driver->load != NULL) { 12685718399fSFrançois Tigeot DRM_LOCK(dev); 12695718399fSFrançois Tigeot /* Shared code returns -errno. */ 12705718399fSFrançois Tigeot retcode = -dev->driver->load(dev, 12715718399fSFrançois Tigeot dev->id_entry->driver_private); 12726df74fa7SFrançois Tigeot if (pci_enable_busmaster(dev->dev)) 12735718399fSFrançois Tigeot DRM_ERROR("Request to enable bus-master failed.\n"); 12745718399fSFrançois Tigeot DRM_UNLOCK(dev); 12755718399fSFrançois Tigeot if (retcode != 0) 12766f486c69SFrançois Tigeot goto error1; 12775718399fSFrançois Tigeot } 12785718399fSFrançois Tigeot 12797f3c3d6fSHasso Tepper DRM_INFO("Initialized %s %d.%d.%d %s\n", 1280b3705d71SHasso Tepper dev->driver->name, 1281b3705d71SHasso Tepper dev->driver->major, 1282b3705d71SHasso Tepper dev->driver->minor, 1283b3705d71SHasso Tepper dev->driver->patchlevel, 1284b3705d71SHasso Tepper dev->driver->date); 12857f3c3d6fSHasso Tepper 12867f3c3d6fSHasso Tepper return 0; 12877f3c3d6fSHasso Tepper 12885718399fSFrançois Tigeot error1: 12896f486c69SFrançois Tigeot drm_gem_destroy(dev); 12907f3c3d6fSHasso Tepper error: 12917f3c3d6fSHasso Tepper drm_sysctl_cleanup(dev); 12925718399fSFrançois Tigeot DRM_LOCK(dev); 12937f3c3d6fSHasso Tepper drm_lastclose(dev); 12945718399fSFrançois Tigeot DRM_UNLOCK(dev); 12955718399fSFrançois Tigeot if (dev->devnode != NULL) 12967f3c3d6fSHasso Tepper destroy_dev(dev->devnode); 1297b3705d71SHasso Tepper 12985718399fSFrançois Tigeot lockuninit(&dev->vbl_lock); 12995718399fSFrançois Tigeot lockuninit(&dev->dev_lock); 13005718399fSFrançois Tigeot lockuninit(&dev->event_lock); 1301a2fdbec6SFrançois Tigeot lockuninit(&dev->struct_mutex); 1302b3705d71SHasso Tepper 13037f3c3d6fSHasso Tepper return retcode; 13047f3c3d6fSHasso Tepper } 13057f3c3d6fSHasso Tepper 13063994a83eSMarkus Pfeiffer /* 13073994a83eSMarkus Pfeiffer * Stub is needed for devfs 13083994a83eSMarkus Pfeiffer */ 13092c845b81SSimon Schubert int drm_close(struct dev_close_args *ap) 13107f3c3d6fSHasso Tepper { 13113994a83eSMarkus Pfeiffer return 0; 13123994a83eSMarkus Pfeiffer } 13137f3c3d6fSHasso Tepper 131479f713b0SFrançois Tigeot void drm_cdevpriv_dtor(void *cd) 131579f713b0SFrançois Tigeot { 131679f713b0SFrançois Tigeot struct drm_file *file_priv = cd; 131779f713b0SFrançois Tigeot struct drm_device *dev = file_priv->dev; 131879f713b0SFrançois Tigeot int retcode = 0; 131979f713b0SFrançois Tigeot 132079f713b0SFrançois Tigeot DRM_DEBUG("open_count = %d\n", dev->open_count); 132179f713b0SFrançois Tigeot 132279f713b0SFrançois Tigeot DRM_LOCK(dev); 132379f713b0SFrançois Tigeot 132479f713b0SFrançois Tigeot if (dev->driver->preclose != NULL) 132579f713b0SFrançois Tigeot dev->driver->preclose(dev, file_priv); 132679f713b0SFrançois Tigeot 132779f713b0SFrançois Tigeot /* ======================================================== 132879f713b0SFrançois Tigeot * Begin inline drm_release 132979f713b0SFrançois Tigeot */ 133079f713b0SFrançois Tigeot 133179f713b0SFrançois Tigeot DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n", 133279f713b0SFrançois Tigeot DRM_CURRENTPID, (long)dev->dev, dev->open_count); 133379f713b0SFrançois Tigeot 133479f713b0SFrançois Tigeot if (dev->driver->driver_features & DRIVER_GEM) 133579f713b0SFrançois Tigeot drm_gem_release(dev, file_priv); 133679f713b0SFrançois Tigeot 133779f713b0SFrançois Tigeot if (dev->lock.hw_lock && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) 133879f713b0SFrançois Tigeot && dev->lock.file_priv == file_priv) { 133979f713b0SFrançois Tigeot DRM_DEBUG("Process %d dead, freeing lock for context %d\n", 134079f713b0SFrançois Tigeot DRM_CURRENTPID, 134179f713b0SFrançois Tigeot _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); 134279f713b0SFrançois Tigeot if (dev->driver->reclaim_buffers_locked != NULL) 134379f713b0SFrançois Tigeot dev->driver->reclaim_buffers_locked(dev, file_priv); 134479f713b0SFrançois Tigeot 134579f713b0SFrançois Tigeot drm_lock_free(&dev->lock, 134679f713b0SFrançois Tigeot _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); 134779f713b0SFrançois Tigeot 134879f713b0SFrançois Tigeot /* FIXME: may require heavy-handed reset of 134979f713b0SFrançois Tigeot hardware at this point, possibly 135079f713b0SFrançois Tigeot processed via a callback to the X 135179f713b0SFrançois Tigeot server. */ 135279f713b0SFrançois Tigeot } else if (dev->driver->reclaim_buffers_locked != NULL && 135379f713b0SFrançois Tigeot dev->lock.hw_lock != NULL) { 135479f713b0SFrançois Tigeot /* The lock is required to reclaim buffers */ 135579f713b0SFrançois Tigeot for (;;) { 135679f713b0SFrançois Tigeot if (!dev->lock.hw_lock) { 135779f713b0SFrançois Tigeot /* Device has been unregistered */ 135879f713b0SFrançois Tigeot retcode = EINTR; 135979f713b0SFrançois Tigeot break; 136079f713b0SFrançois Tigeot } 136179f713b0SFrançois Tigeot /* Contention */ 136279f713b0SFrançois Tigeot retcode = DRM_LOCK_SLEEP(dev, &dev->lock.lock_queue, 136379f713b0SFrançois Tigeot PCATCH, "drmlk2", 0); 136479f713b0SFrançois Tigeot if (retcode) 136579f713b0SFrançois Tigeot break; 136679f713b0SFrançois Tigeot } 136779f713b0SFrançois Tigeot if (retcode == 0) { 136879f713b0SFrançois Tigeot dev->driver->reclaim_buffers_locked(dev, file_priv); 136979f713b0SFrançois Tigeot } 137079f713b0SFrançois Tigeot } 137179f713b0SFrançois Tigeot 137279f713b0SFrançois Tigeot if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) && 137379f713b0SFrançois Tigeot !dev->driver->reclaim_buffers_locked) 137479f713b0SFrançois Tigeot drm_reclaim_buffers(dev, file_priv); 137579f713b0SFrançois Tigeot 137679f713b0SFrançois Tigeot funsetown(&dev->buf_sigio); 137779f713b0SFrançois Tigeot 137879f713b0SFrançois Tigeot if (dev->driver->postclose != NULL) 137979f713b0SFrançois Tigeot dev->driver->postclose(dev, file_priv); 138079f713b0SFrançois Tigeot list_del(&file_priv->lhead); 138179f713b0SFrançois Tigeot 138279f713b0SFrançois Tigeot 138379f713b0SFrançois Tigeot /* ======================================================== 138479f713b0SFrançois Tigeot * End inline drm_release 138579f713b0SFrançois Tigeot */ 138679f713b0SFrançois Tigeot 138779f713b0SFrançois Tigeot atomic_inc(&dev->counts[_DRM_STAT_CLOSES]); 138879f713b0SFrançois Tigeot device_unbusy(dev->dev); 138979f713b0SFrançois Tigeot if (--dev->open_count == 0) { 139079f713b0SFrançois Tigeot retcode = drm_lastclose(dev); 139179f713b0SFrançois Tigeot } 139279f713b0SFrançois Tigeot 139379f713b0SFrançois Tigeot DRM_UNLOCK(dev); 139479f713b0SFrançois Tigeot } 139579f713b0SFrançois Tigeot 1396b3705d71SHasso Tepper drm_local_map_t *drm_getsarea(struct drm_device *dev) 13977f3c3d6fSHasso Tepper { 1398f599cd46SFrançois Tigeot struct drm_map_list *entry; 13997f3c3d6fSHasso Tepper 1400f599cd46SFrançois Tigeot list_for_each_entry(entry, &dev->maplist, head) { 1401f599cd46SFrançois Tigeot if (entry->map && entry->map->type == _DRM_SHM && 1402f599cd46SFrançois Tigeot (entry->map->flags & _DRM_CONTAINS_LOCK)) { 1403f599cd46SFrançois Tigeot return entry->map; 1404f599cd46SFrançois Tigeot } 14057f3c3d6fSHasso Tepper } 14067f3c3d6fSHasso Tepper 14077f3c3d6fSHasso Tepper return NULL; 14087f3c3d6fSHasso Tepper } 14097f3c3d6fSHasso Tepper 14105718399fSFrançois Tigeot int 14115718399fSFrançois Tigeot drm_add_busid_modesetting(struct drm_device *dev, struct sysctl_ctx_list *ctx, 14125718399fSFrançois Tigeot struct sysctl_oid *top) 14135718399fSFrançois Tigeot { 14145718399fSFrançois Tigeot struct sysctl_oid *oid; 14155718399fSFrançois Tigeot 14165718399fSFrançois Tigeot ksnprintf(dev->busid_str, sizeof(dev->busid_str), 14175718399fSFrançois Tigeot "pci:%04x:%02x:%02x.%d", dev->pci_domain, dev->pci_bus, 14185718399fSFrançois Tigeot dev->pci_slot, dev->pci_func); 14195718399fSFrançois Tigeot oid = SYSCTL_ADD_STRING(ctx, SYSCTL_CHILDREN(top), OID_AUTO, "busid", 14205718399fSFrançois Tigeot CTLFLAG_RD, dev->busid_str, 0, NULL); 14215718399fSFrançois Tigeot if (oid == NULL) 14225718399fSFrançois Tigeot return (ENOMEM); 14235718399fSFrançois Tigeot dev->modesetting = (dev->driver->driver_features & DRIVER_MODESET) != 0; 14245718399fSFrançois Tigeot oid = SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(top), OID_AUTO, 14255718399fSFrançois Tigeot "modesetting", CTLFLAG_RD, &dev->modesetting, 0, NULL); 14265718399fSFrançois Tigeot if (oid == NULL) 14275718399fSFrançois Tigeot return (ENOMEM); 14285718399fSFrançois Tigeot 14295718399fSFrançois Tigeot return (0); 14305718399fSFrançois Tigeot } 14315718399fSFrançois Tigeot 14325718399fSFrançois Tigeot int 14335718399fSFrançois Tigeot drm_mmap_single(struct dev_mmap_single_args *ap) 14345718399fSFrançois Tigeot { 143579f713b0SFrançois Tigeot struct drm_device *dev; 14365718399fSFrançois Tigeot struct cdev *kdev = ap->a_head.a_dev; 14375718399fSFrançois Tigeot vm_ooffset_t *offset = ap->a_offset; 14385718399fSFrançois Tigeot vm_size_t size = ap->a_size; 14395718399fSFrançois Tigeot struct vm_object **obj_res = ap->a_object; 14405718399fSFrançois Tigeot int nprot = ap->a_nprot; 14415718399fSFrançois Tigeot 144279f713b0SFrançois Tigeot dev = drm_get_device_from_kdev(kdev); 14436f486c69SFrançois Tigeot if (dev->drm_ttm_bdev != NULL) { 14446f486c69SFrançois Tigeot return (ttm_bo_mmap_single(dev->drm_ttm_bdev, offset, size, 14455718399fSFrançois Tigeot obj_res, nprot)); 14466f486c69SFrançois Tigeot } else if ((dev->driver->driver_features & DRIVER_GEM) != 0) { 14476f486c69SFrançois Tigeot return (drm_gem_mmap_single(dev, offset, size, obj_res, nprot)); 14485718399fSFrançois Tigeot } else { 14495718399fSFrançois Tigeot return (ENODEV); 14505718399fSFrançois Tigeot } 14515718399fSFrançois Tigeot } 14525718399fSFrançois Tigeot 14537f3c3d6fSHasso Tepper #if DRM_LINUX 14547f3c3d6fSHasso Tepper 14557f3c3d6fSHasso Tepper #include <sys/sysproto.h> 14567f3c3d6fSHasso Tepper 14577f3c3d6fSHasso Tepper MODULE_DEPEND(DRIVER_NAME, linux, 1, 1, 1); 14587f3c3d6fSHasso Tepper 14597f3c3d6fSHasso Tepper #define LINUX_IOCTL_DRM_MIN 0x6400 14607f3c3d6fSHasso Tepper #define LINUX_IOCTL_DRM_MAX 0x64ff 14617f3c3d6fSHasso Tepper 14627f3c3d6fSHasso Tepper static linux_ioctl_function_t drm_linux_ioctl; 14637f3c3d6fSHasso Tepper static struct linux_ioctl_handler drm_handler = {drm_linux_ioctl, 14647f3c3d6fSHasso Tepper LINUX_IOCTL_DRM_MIN, LINUX_IOCTL_DRM_MAX}; 14657f3c3d6fSHasso Tepper 14667f3c3d6fSHasso Tepper /* The bits for in/out are switched on Linux */ 14677f3c3d6fSHasso Tepper #define LINUX_IOC_IN IOC_OUT 14687f3c3d6fSHasso Tepper #define LINUX_IOC_OUT IOC_IN 14697f3c3d6fSHasso Tepper 14707f3c3d6fSHasso Tepper static int 14717f3c3d6fSHasso Tepper drm_linux_ioctl(DRM_STRUCTPROC *p, struct linux_ioctl_args* args) 14727f3c3d6fSHasso Tepper { 14737f3c3d6fSHasso Tepper int error; 14747f3c3d6fSHasso Tepper int cmd = args->cmd; 14757f3c3d6fSHasso Tepper 14767f3c3d6fSHasso Tepper args->cmd &= ~(LINUX_IOC_IN | LINUX_IOC_OUT); 14777f3c3d6fSHasso Tepper if (cmd & LINUX_IOC_IN) 14787f3c3d6fSHasso Tepper args->cmd |= IOC_IN; 14797f3c3d6fSHasso Tepper if (cmd & LINUX_IOC_OUT) 14807f3c3d6fSHasso Tepper args->cmd |= IOC_OUT; 14817f3c3d6fSHasso Tepper 14827f3c3d6fSHasso Tepper error = ioctl(p, (struct ioctl_args *)args); 14837f3c3d6fSHasso Tepper 14847f3c3d6fSHasso Tepper return error; 14857f3c3d6fSHasso Tepper } 14867f3c3d6fSHasso Tepper #endif /* DRM_LINUX */ 14875718399fSFrançois Tigeot 14886f486c69SFrançois Tigeot static int 14896f486c69SFrançois Tigeot drm_core_init(void *arg) 14906f486c69SFrançois Tigeot { 14916f486c69SFrançois Tigeot 14926f486c69SFrançois Tigeot drm_global_init(); 14936f486c69SFrançois Tigeot 14946f486c69SFrançois Tigeot #if DRM_LINUX 14956f486c69SFrançois Tigeot linux_ioctl_register_handler(&drm_handler); 14966f486c69SFrançois Tigeot #endif /* DRM_LINUX */ 14976f486c69SFrançois Tigeot 14986f486c69SFrançois Tigeot DRM_INFO("Initialized %s %d.%d.%d %s\n", 14996f486c69SFrançois Tigeot CORE_NAME, CORE_MAJOR, CORE_MINOR, CORE_PATCHLEVEL, CORE_DATE); 15006f486c69SFrançois Tigeot return 0; 15016f486c69SFrançois Tigeot } 15026f486c69SFrançois Tigeot 15036f486c69SFrançois Tigeot static void 15046f486c69SFrançois Tigeot drm_core_exit(void *arg) 15056f486c69SFrançois Tigeot { 15066f486c69SFrançois Tigeot 15076f486c69SFrançois Tigeot #if DRM_LINUX 15086f486c69SFrançois Tigeot linux_ioctl_unregister_handler(&drm_handler); 15096f486c69SFrançois Tigeot #endif /* DRM_LINUX */ 15106f486c69SFrançois Tigeot 15116f486c69SFrançois Tigeot drm_global_release(); 15126f486c69SFrançois Tigeot } 15136f486c69SFrançois Tigeot 15146f486c69SFrançois Tigeot SYSINIT(drm_register, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, 15156f486c69SFrançois Tigeot drm_core_init, NULL); 15166f486c69SFrançois Tigeot SYSUNINIT(drm_unregister, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, 15176f486c69SFrançois Tigeot drm_core_exit, NULL); 15186f486c69SFrançois Tigeot 1519*24edb884SFrançois Tigeot 1520*24edb884SFrançois Tigeot #include <linux/dmi.h> 1521*24edb884SFrançois Tigeot 15225718399fSFrançois Tigeot /* 15235718399fSFrançois Tigeot * Check if dmi_system_id structure matches system DMI data 15245718399fSFrançois Tigeot */ 15255718399fSFrançois Tigeot static bool 15265718399fSFrançois Tigeot dmi_found(const struct dmi_system_id *dsi) 15275718399fSFrançois Tigeot { 15285718399fSFrançois Tigeot int i, slot; 15295718399fSFrançois Tigeot bool found = false; 15305718399fSFrançois Tigeot char *sys_vendor, *board_vendor, *product_name, *board_name; 15315718399fSFrançois Tigeot 15325718399fSFrançois Tigeot sys_vendor = kgetenv("smbios.system.maker"); 15335718399fSFrançois Tigeot board_vendor = kgetenv("smbios.planar.maker"); 15345718399fSFrançois Tigeot product_name = kgetenv("smbios.system.product"); 15355718399fSFrançois Tigeot board_name = kgetenv("smbios.planar.product"); 15365718399fSFrançois Tigeot 15375718399fSFrançois Tigeot for (i = 0; i < NELEM(dsi->matches); i++) { 15385718399fSFrançois Tigeot slot = dsi->matches[i].slot; 15395718399fSFrançois Tigeot switch (slot) { 15405718399fSFrançois Tigeot case DMI_NONE: 15415718399fSFrançois Tigeot break; 15425718399fSFrançois Tigeot case DMI_SYS_VENDOR: 15435718399fSFrançois Tigeot if (sys_vendor != NULL && 15445718399fSFrançois Tigeot !strcmp(sys_vendor, dsi->matches[i].substr)) 15455718399fSFrançois Tigeot break; 15465718399fSFrançois Tigeot else 15475718399fSFrançois Tigeot goto done; 15485718399fSFrançois Tigeot case DMI_BOARD_VENDOR: 15495718399fSFrançois Tigeot if (board_vendor != NULL && 15505718399fSFrançois Tigeot !strcmp(board_vendor, dsi->matches[i].substr)) 15515718399fSFrançois Tigeot break; 15525718399fSFrançois Tigeot else 15535718399fSFrançois Tigeot goto done; 15545718399fSFrançois Tigeot case DMI_PRODUCT_NAME: 15555718399fSFrançois Tigeot if (product_name != NULL && 15565718399fSFrançois Tigeot !strcmp(product_name, dsi->matches[i].substr)) 15575718399fSFrançois Tigeot break; 15585718399fSFrançois Tigeot else 15595718399fSFrançois Tigeot goto done; 15605718399fSFrançois Tigeot case DMI_BOARD_NAME: 15615718399fSFrançois Tigeot if (board_name != NULL && 15625718399fSFrançois Tigeot !strcmp(board_name, dsi->matches[i].substr)) 15635718399fSFrançois Tigeot break; 15645718399fSFrançois Tigeot else 15655718399fSFrançois Tigeot goto done; 15665718399fSFrançois Tigeot default: 15675718399fSFrançois Tigeot goto done; 15685718399fSFrançois Tigeot } 15695718399fSFrançois Tigeot } 15705718399fSFrançois Tigeot found = true; 15715718399fSFrançois Tigeot 15725718399fSFrançois Tigeot done: 15735718399fSFrançois Tigeot if (sys_vendor != NULL) 15745718399fSFrançois Tigeot kfreeenv(sys_vendor); 15755718399fSFrançois Tigeot if (board_vendor != NULL) 15765718399fSFrançois Tigeot kfreeenv(board_vendor); 15775718399fSFrançois Tigeot if (product_name != NULL) 15785718399fSFrançois Tigeot kfreeenv(product_name); 15795718399fSFrançois Tigeot if (board_name != NULL) 15805718399fSFrançois Tigeot kfreeenv(board_name); 15815718399fSFrançois Tigeot 15825718399fSFrançois Tigeot return found; 15835718399fSFrançois Tigeot } 15845718399fSFrançois Tigeot 1585be348e9fSFrançois Tigeot int dmi_check_system(const struct dmi_system_id *sysid) 15865718399fSFrançois Tigeot { 15875718399fSFrançois Tigeot const struct dmi_system_id *dsi; 15885718399fSFrançois Tigeot int num = 0; 15895718399fSFrançois Tigeot 15905718399fSFrançois Tigeot for (dsi = sysid; dsi->matches[0].slot != 0 ; dsi++) { 15915718399fSFrançois Tigeot if (dmi_found(dsi)) { 15925718399fSFrançois Tigeot num++; 15935718399fSFrançois Tigeot if (dsi->callback && dsi->callback(dsi)) 15945718399fSFrançois Tigeot break; 15955718399fSFrançois Tigeot } 15965718399fSFrançois Tigeot } 15975718399fSFrançois Tigeot return (num); 15985718399fSFrançois Tigeot } 1599