Loading drivers/gpu/drm/drm_drv.c +2 −2 Original line number Diff line number Diff line Loading @@ -344,7 +344,7 @@ long drm_ioctl(struct file *filp, DRM_DEBUG("pid=%d, dev=0x%lx, auth=%d, %s\n", task_pid_nr(current), (long)old_encode_dev(file_priv->minor->device), (long)old_encode_dev(file_priv->minor->kdev->devt), file_priv->authenticated, ioctl->name); /* Do not trust userspace, use our own definition */ Loading Loading @@ -402,7 +402,7 @@ long drm_ioctl(struct file *filp, if (!ioctl) DRM_DEBUG("invalid ioctl: pid=%d, dev=0x%lx, auth=%d, cmd=0x%02x, nr=0x%02x\n", task_pid_nr(current), (long)old_encode_dev(file_priv->minor->device), (long)old_encode_dev(file_priv->minor->kdev->devt), file_priv->authenticated, cmd, nr); if (kdata != stack_kdata) Loading drivers/gpu/drm/drm_fops.c +30 −40 Original line number Diff line number Diff line Loading @@ -39,12 +39,12 @@ #include <linux/slab.h> #include <linux/module.h> /* from BKL pushdown: note that nothing else serializes idr_find() */ /* from BKL pushdown */ DEFINE_MUTEX(drm_global_mutex); EXPORT_SYMBOL(drm_global_mutex); static int drm_open_helper(struct inode *inode, struct file *filp, struct drm_device * dev); struct drm_minor *minor); static int drm_setup(struct drm_device * dev) { Loading Loading @@ -79,29 +79,23 @@ static int drm_setup(struct drm_device * dev) */ int drm_open(struct inode *inode, struct file *filp) { struct drm_device *dev = NULL; int minor_id = iminor(inode); struct drm_device *dev; struct drm_minor *minor; int retcode = 0; int retcode; int need_setup = 0; minor = idr_find(&drm_minors_idr, minor_id); if (!minor) return -ENODEV; if (!(dev = minor->dev)) return -ENODEV; if (drm_device_is_unplugged(dev)) return -ENODEV; minor = drm_minor_acquire(iminor(inode)); if (IS_ERR(minor)) return PTR_ERR(minor); dev = minor->dev; if (!dev->open_count++) need_setup = 1; /* share address_space across all char-devs of a single device */ filp->f_mapping = dev->anon_inode->i_mapping; retcode = drm_open_helper(inode, filp, dev); retcode = drm_open_helper(inode, filp, minor); if (retcode) goto err_undo; if (need_setup) { Loading @@ -113,6 +107,7 @@ int drm_open(struct inode *inode, struct file *filp) err_undo: dev->open_count--; drm_minor_release(minor); return retcode; } EXPORT_SYMBOL(drm_open); Loading @@ -128,33 +123,30 @@ EXPORT_SYMBOL(drm_open); */ int drm_stub_open(struct inode *inode, struct file *filp) { struct drm_device *dev = NULL; struct drm_device *dev; struct drm_minor *minor; int minor_id = iminor(inode); int err = -ENODEV; const struct file_operations *new_fops; DRM_DEBUG("\n"); mutex_lock(&drm_global_mutex); minor = idr_find(&drm_minors_idr, minor_id); if (!minor) goto out; if (!(dev = minor->dev)) goto out; if (drm_device_is_unplugged(dev)) goto out; minor = drm_minor_acquire(iminor(inode)); if (IS_ERR(minor)) goto out_unlock; dev = minor->dev; new_fops = fops_get(dev->driver->fops); if (!new_fops) goto out; goto out_release; replace_fops(filp, new_fops); if (filp->f_op->open) err = filp->f_op->open(inode, filp); out: out_release: drm_minor_release(minor); out_unlock: mutex_unlock(&drm_global_mutex); return err; } Loading @@ -181,16 +173,16 @@ static int drm_cpu_valid(void) * * \param inode device inode. * \param filp file pointer. * \param dev device. * \param minor acquired minor-object. * \return zero on success or a negative number on failure. * * Creates and initializes a drm_file structure for the file private data in \p * filp and add it into the double linked list in \p dev. */ static int drm_open_helper(struct inode *inode, struct file *filp, struct drm_device * dev) struct drm_minor *minor) { int minor_id = iminor(inode); struct drm_device *dev = minor->dev; struct drm_file *priv; int ret; Loading @@ -201,7 +193,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp, if (dev->switch_power_state != DRM_SWITCH_POWER_ON && dev->switch_power_state != DRM_SWITCH_POWER_DYNAMIC_OFF) return -EINVAL; DRM_DEBUG("pid = %d, minor = %d\n", task_pid_nr(current), minor_id); DRM_DEBUG("pid = %d, minor = %d\n", task_pid_nr(current), minor->index); priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) Loading @@ -211,11 +203,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp, priv->filp = filp; priv->uid = current_euid(); priv->pid = get_pid(task_pid(current)); priv->minor = idr_find(&drm_minors_idr, minor_id); if (!priv->minor) { ret = -ENODEV; goto out_put_pid; } priv->minor = minor; /* for compatibility root is always authenticated */ priv->always_authenticated = capable(CAP_SYS_ADMIN); Loading Loading @@ -321,7 +309,6 @@ static int drm_open_helper(struct inode *inode, struct file *filp, drm_prime_destroy_file_private(&priv->prime); if (dev->driver->driver_features & DRIVER_GEM) drm_gem_release(dev, priv); out_put_pid: put_pid(priv->pid); kfree(priv); filp->private_data = NULL; Loading Loading @@ -442,7 +429,8 @@ int drm_lastclose(struct drm_device * dev) int drm_release(struct inode *inode, struct file *filp) { struct drm_file *file_priv = filp->private_data; struct drm_device *dev = file_priv->minor->dev; struct drm_minor *minor = file_priv->minor; struct drm_device *dev = minor->dev; int retcode = 0; mutex_lock(&drm_global_mutex); Loading @@ -458,7 +446,7 @@ int drm_release(struct inode *inode, struct file *filp) DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n", task_pid_nr(current), (long)old_encode_dev(file_priv->minor->device), (long)old_encode_dev(file_priv->minor->kdev->devt), dev->open_count); /* Release any auth tokens that might point to this file_priv, Loading Loading @@ -561,6 +549,8 @@ int drm_release(struct inode *inode, struct file *filp) } mutex_unlock(&drm_global_mutex); drm_minor_release(minor); return retcode; } EXPORT_SYMBOL(drm_release); Loading drivers/gpu/drm/drm_pci.c +1 −1 Original line number Diff line number Diff line Loading @@ -351,7 +351,7 @@ int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent, drm_pci_agp_destroy(dev); pci_disable_device(pdev); err_free: drm_dev_free(dev); drm_dev_unref(dev); return ret; } EXPORT_SYMBOL(drm_get_pci_dev); Loading drivers/gpu/drm/drm_platform.c +1 −1 Original line number Diff line number Diff line Loading @@ -64,7 +64,7 @@ static int drm_get_platform_dev(struct platform_device *platdev, return 0; err_free: drm_dev_free(dev); drm_dev_unref(dev); return ret; } Loading drivers/gpu/drm/drm_stub.c +216 −132 Original line number Diff line number Diff line Loading @@ -72,6 +72,7 @@ module_param_named(vblankoffdelay, drm_vblank_offdelay, int, 0600); module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600); module_param_named(timestamp_monotonic, drm_timestamp_monotonic, int, 0600); static DEFINE_SPINLOCK(drm_minor_lock); struct idr drm_minors_idr; struct class *drm_class; Loading Loading @@ -119,26 +120,6 @@ void drm_ut_debug_printk(unsigned int request_level, } EXPORT_SYMBOL(drm_ut_debug_printk); static int drm_minor_get_id(struct drm_device *dev, int type) { int ret; int base = 0, limit = 63; if (type == DRM_MINOR_CONTROL) { base += 64; limit = base + 63; } else if (type == DRM_MINOR_RENDER) { base += 128; limit = base + 63; } mutex_lock(&dev->struct_mutex); ret = idr_alloc(&drm_minors_idr, NULL, base, limit, GFP_KERNEL); mutex_unlock(&dev->struct_mutex); return ret == -ENOSPC ? -EINVAL : ret; } struct drm_master *drm_master_create(struct drm_minor *minor) { struct drm_master *master; Loading Loading @@ -262,119 +243,183 @@ int drm_dropmaster_ioctl(struct drm_device *dev, void *data, return 0; } /** * drm_get_minor - Allocate and register new DRM minor * @dev: DRM device * @minor: Pointer to where new minor is stored * @type: Type of minor * * Allocate a new minor of the given type and register it. A pointer to the new * minor is returned in @minor. * Caller must hold the global DRM mutex. /* * DRM Minors * A DRM device can provide several char-dev interfaces on the DRM-Major. Each * of them is represented by a drm_minor object. Depending on the capabilities * of the device-driver, different interfaces are registered. * * RETURNS: * 0 on success, negative error code on failure. * Minors can be accessed via dev->$minor_name. This pointer is either * NULL or a valid drm_minor pointer and stays valid as long as the device is * valid. This means, DRM minors have the same life-time as the underlying * device. However, this doesn't mean that the minor is active. Minors are * registered and unregistered dynamically according to device-state. */ static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int type) static struct drm_minor **drm_minor_get_slot(struct drm_device *dev, unsigned int type) { switch (type) { case DRM_MINOR_LEGACY: return &dev->primary; case DRM_MINOR_RENDER: return &dev->render; case DRM_MINOR_CONTROL: return &dev->control; default: return NULL; } } static int drm_minor_alloc(struct drm_device *dev, unsigned int type) { struct drm_minor *minor; minor = kzalloc(sizeof(*minor), GFP_KERNEL); if (!minor) return -ENOMEM; minor->type = type; minor->dev = dev; INIT_LIST_HEAD(&minor->master_list); *drm_minor_get_slot(dev, type) = minor; return 0; } static void drm_minor_free(struct drm_device *dev, unsigned int type) { struct drm_minor **slot; slot = drm_minor_get_slot(dev, type); if (*slot) { kfree(*slot); *slot = NULL; } } static int drm_minor_register(struct drm_device *dev, unsigned int type) { struct drm_minor *new_minor; unsigned long flags; int ret; int minor_id; DRM_DEBUG("\n"); minor_id = drm_minor_get_id(dev, type); new_minor = *drm_minor_get_slot(dev, type); if (!new_minor) return 0; idr_preload(GFP_KERNEL); spin_lock_irqsave(&drm_minor_lock, flags); minor_id = idr_alloc(&drm_minors_idr, NULL, 64 * type, 64 * (type + 1), GFP_NOWAIT); spin_unlock_irqrestore(&drm_minor_lock, flags); idr_preload_end(); if (minor_id < 0) return minor_id; new_minor = kzalloc(sizeof(struct drm_minor), GFP_KERNEL); if (!new_minor) { ret = -ENOMEM; goto err_idr; } new_minor->type = type; new_minor->device = MKDEV(DRM_MAJOR, minor_id); new_minor->dev = dev; new_minor->index = minor_id; INIT_LIST_HEAD(&new_minor->master_list); idr_replace(&drm_minors_idr, new_minor, minor_id); #if defined(CONFIG_DEBUG_FS) ret = drm_debugfs_init(new_minor, minor_id, drm_debugfs_root); if (ret) { DRM_ERROR("DRM: Failed to initialize /sys/kernel/debug/dri.\n"); goto err_mem; goto err_id; } #endif ret = drm_sysfs_device_add(new_minor); if (ret) { printk(KERN_ERR "DRM: Error sysfs_device_add.\n"); DRM_ERROR("DRM: Error sysfs_device_add.\n"); goto err_debugfs; } *minor = new_minor; /* replace NULL with @minor so lookups will succeed from now on */ spin_lock_irqsave(&drm_minor_lock, flags); idr_replace(&drm_minors_idr, new_minor, new_minor->index); spin_unlock_irqrestore(&drm_minor_lock, flags); DRM_DEBUG("new minor assigned %d\n", minor_id); return 0; err_debugfs: #if defined(CONFIG_DEBUG_FS) drm_debugfs_cleanup(new_minor); err_mem: #endif kfree(new_minor); err_idr: err_id: spin_lock_irqsave(&drm_minor_lock, flags); idr_remove(&drm_minors_idr, minor_id); *minor = NULL; spin_unlock_irqrestore(&drm_minor_lock, flags); new_minor->index = 0; return ret; } /** * drm_unplug_minor - Unplug DRM minor * @minor: Minor to unplug * * Unplugs the given DRM minor but keeps the object. So after this returns, * minor->dev is still valid so existing open-files can still access it to get * device information from their drm_file ojects. * If the minor is already unplugged or if @minor is NULL, nothing is done. * The global DRM mutex must be held by the caller. */ static void drm_unplug_minor(struct drm_minor *minor) static void drm_minor_unregister(struct drm_device *dev, unsigned int type) { struct drm_minor *minor; unsigned long flags; minor = *drm_minor_get_slot(dev, type); if (!minor || !minor->kdev) return; #if defined(CONFIG_DEBUG_FS) drm_debugfs_cleanup(minor); #endif spin_lock_irqsave(&drm_minor_lock, flags); idr_remove(&drm_minors_idr, minor->index); spin_unlock_irqrestore(&drm_minor_lock, flags); minor->index = 0; drm_debugfs_cleanup(minor); drm_sysfs_device_remove(minor); idr_remove(&drm_minors_idr, minor->index); } /** * drm_put_minor - Destroy DRM minor * @minor: Minor to destroy * drm_minor_acquire - Acquire a DRM minor * @minor_id: Minor ID of the DRM-minor * * Looks up the given minor-ID and returns the respective DRM-minor object. The * refence-count of the underlying device is increased so you must release this * object with drm_minor_release(). * * This calls drm_unplug_minor() on the given minor and then frees it. Nothing * is done if @minor is NULL. It is fine to call this on already unplugged * minors. * The global DRM mutex must be held by the caller. * As long as you hold this minor, it is guaranteed that the object and the * minor->dev pointer will stay valid! However, the device may get unplugged and * unregistered while you hold the minor. * * Returns: * Pointer to minor-object with increased device-refcount, or PTR_ERR on * failure. */ static void drm_put_minor(struct drm_minor *minor) struct drm_minor *drm_minor_acquire(unsigned int minor_id) { if (!minor) return; struct drm_minor *minor; unsigned long flags; DRM_DEBUG("release secondary minor %d\n", minor->index); spin_lock_irqsave(&drm_minor_lock, flags); minor = idr_find(&drm_minors_idr, minor_id); if (minor) drm_dev_ref(minor->dev); spin_unlock_irqrestore(&drm_minor_lock, flags); drm_unplug_minor(minor); kfree(minor); if (!minor) { return ERR_PTR(-ENODEV); } else if (drm_device_is_unplugged(minor->dev)) { drm_dev_unref(minor->dev); return ERR_PTR(-ENODEV); } return minor; } /** * drm_minor_release - Release DRM minor * @minor: Pointer to DRM minor object * * Release a minor that was previously acquired via drm_minor_acquire(). */ void drm_minor_release(struct drm_minor *minor) { drm_dev_unref(minor->dev); } /** Loading @@ -394,18 +439,16 @@ void drm_put_dev(struct drm_device *dev) } drm_dev_unregister(dev); drm_dev_free(dev); drm_dev_unref(dev); } EXPORT_SYMBOL(drm_put_dev); void drm_unplug_dev(struct drm_device *dev) { /* for a USB device */ if (drm_core_check_feature(dev, DRIVER_MODESET)) drm_unplug_minor(dev->control); if (dev->render) drm_unplug_minor(dev->render); drm_unplug_minor(dev->primary); drm_minor_unregister(dev, DRM_MINOR_LEGACY); drm_minor_unregister(dev, DRM_MINOR_RENDER); drm_minor_unregister(dev, DRM_MINOR_CONTROL); mutex_lock(&drm_global_mutex); Loading Loading @@ -499,6 +542,9 @@ static void drm_fs_inode_free(struct inode *inode) * Call drm_dev_register() to advertice the device to user space and register it * with other core subsystems. * * The initial ref-count of the object is 1. Use drm_dev_ref() and * drm_dev_unref() to take and drop further ref-counts. * * RETURNS: * Pointer to new DRM device, or NULL if out of memory. */ Loading @@ -512,6 +558,7 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver, if (!dev) return NULL; kref_init(&dev->ref); dev->dev = parent; dev->driver = driver; Loading @@ -533,8 +580,24 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver, goto err_free; } if (drm_core_check_feature(dev, DRIVER_MODESET)) { ret = drm_minor_alloc(dev, DRM_MINOR_CONTROL); if (ret) goto err_minors; } if (drm_core_check_feature(dev, DRIVER_RENDER) && drm_rnodes) { ret = drm_minor_alloc(dev, DRM_MINOR_RENDER); if (ret) goto err_minors; } ret = drm_minor_alloc(dev, DRM_MINOR_LEGACY); if (ret) goto err_minors; if (drm_ht_create(&dev->map_hash, 12)) goto err_inode; goto err_minors; ret = drm_ctxbitmap_init(dev); if (ret) { Loading @@ -556,7 +619,10 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver, drm_ctxbitmap_cleanup(dev); err_ht: drm_ht_remove(&dev->map_hash); err_inode: err_minors: drm_minor_free(dev, DRM_MINOR_LEGACY); drm_minor_free(dev, DRM_MINOR_RENDER); drm_minor_free(dev, DRM_MINOR_CONTROL); drm_fs_inode_free(dev->anon_inode); err_free: kfree(dev); Loading @@ -564,21 +630,9 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver, } EXPORT_SYMBOL(drm_dev_alloc); /** * drm_dev_free - Free DRM device * @dev: DRM device to free * * Free a DRM device that has previously been allocated via drm_dev_alloc(). * You must not use kfree() instead or you will leak memory. * * This must not be called once the device got registered. Use drm_put_dev() * instead, which then calls drm_dev_free(). */ void drm_dev_free(struct drm_device *dev) static void drm_dev_release(struct kref *ref) { drm_put_minor(dev->control); drm_put_minor(dev->render); drm_put_minor(dev->primary); struct drm_device *dev = container_of(ref, struct drm_device, ref); if (dev->driver->driver_features & DRIVER_GEM) drm_gem_destroy(dev); Loading @@ -587,10 +641,46 @@ void drm_dev_free(struct drm_device *dev) drm_ht_remove(&dev->map_hash); drm_fs_inode_free(dev->anon_inode); drm_minor_free(dev, DRM_MINOR_LEGACY); drm_minor_free(dev, DRM_MINOR_RENDER); drm_minor_free(dev, DRM_MINOR_CONTROL); kfree(dev->devname); kfree(dev); } EXPORT_SYMBOL(drm_dev_free); /** * drm_dev_ref - Take reference of a DRM device * @dev: device to take reference of or NULL * * This increases the ref-count of @dev by one. You *must* already own a * reference when calling this. Use drm_dev_unref() to drop this reference * again. * * This function never fails. However, this function does not provide *any* * guarantee whether the device is alive or running. It only provides a * reference to the object and the memory associated with it. */ void drm_dev_ref(struct drm_device *dev) { if (dev) kref_get(&dev->ref); } EXPORT_SYMBOL(drm_dev_ref); /** * drm_dev_unref - Drop reference of a DRM device * @dev: device to drop reference of or NULL * * This decreases the ref-count of @dev by one. The device is destroyed if the * ref-count drops to zero. */ void drm_dev_unref(struct drm_device *dev) { if (dev) kref_put(&dev->ref, drm_dev_release); } EXPORT_SYMBOL(drm_dev_unref); /** * drm_dev_register - Register DRM device Loading @@ -611,26 +701,22 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags) mutex_lock(&drm_global_mutex); if (drm_core_check_feature(dev, DRIVER_MODESET)) { ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL); ret = drm_minor_register(dev, DRM_MINOR_CONTROL); if (ret) goto out_unlock; } goto err_minors; if (drm_core_check_feature(dev, DRIVER_RENDER) && drm_rnodes) { ret = drm_get_minor(dev, &dev->render, DRM_MINOR_RENDER); ret = drm_minor_register(dev, DRM_MINOR_RENDER); if (ret) goto err_control_node; } goto err_minors; ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY); ret = drm_minor_register(dev, DRM_MINOR_LEGACY); if (ret) goto err_render_node; goto err_minors; if (dev->driver->load) { ret = dev->driver->load(dev, flags); if (ret) goto err_primary_node; goto err_minors; } /* setup grouping for legacy outputs */ Loading @@ -647,12 +733,10 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags) err_unload: if (dev->driver->unload) dev->driver->unload(dev); err_primary_node: drm_unplug_minor(dev->primary); err_render_node: drm_unplug_minor(dev->render); err_control_node: drm_unplug_minor(dev->control); err_minors: drm_minor_unregister(dev, DRM_MINOR_LEGACY); drm_minor_unregister(dev, DRM_MINOR_RENDER); drm_minor_unregister(dev, DRM_MINOR_CONTROL); out_unlock: mutex_unlock(&drm_global_mutex); return ret; Loading @@ -665,7 +749,7 @@ EXPORT_SYMBOL(drm_dev_register); * * Unregister the DRM device from the system. This does the reverse of * drm_dev_register() but does not deallocate the device. The caller must call * drm_dev_free() to free all resources. * drm_dev_unref() to drop their final reference. */ void drm_dev_unregister(struct drm_device *dev) { Loading @@ -684,8 +768,8 @@ void drm_dev_unregister(struct drm_device *dev) list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head) drm_rmmap(dev, r_list->map); drm_unplug_minor(dev->control); drm_unplug_minor(dev->render); drm_unplug_minor(dev->primary); drm_minor_unregister(dev, DRM_MINOR_LEGACY); drm_minor_unregister(dev, DRM_MINOR_RENDER); drm_minor_unregister(dev, DRM_MINOR_CONTROL); } EXPORT_SYMBOL(drm_dev_unregister); Loading
drivers/gpu/drm/drm_drv.c +2 −2 Original line number Diff line number Diff line Loading @@ -344,7 +344,7 @@ long drm_ioctl(struct file *filp, DRM_DEBUG("pid=%d, dev=0x%lx, auth=%d, %s\n", task_pid_nr(current), (long)old_encode_dev(file_priv->minor->device), (long)old_encode_dev(file_priv->minor->kdev->devt), file_priv->authenticated, ioctl->name); /* Do not trust userspace, use our own definition */ Loading Loading @@ -402,7 +402,7 @@ long drm_ioctl(struct file *filp, if (!ioctl) DRM_DEBUG("invalid ioctl: pid=%d, dev=0x%lx, auth=%d, cmd=0x%02x, nr=0x%02x\n", task_pid_nr(current), (long)old_encode_dev(file_priv->minor->device), (long)old_encode_dev(file_priv->minor->kdev->devt), file_priv->authenticated, cmd, nr); if (kdata != stack_kdata) Loading
drivers/gpu/drm/drm_fops.c +30 −40 Original line number Diff line number Diff line Loading @@ -39,12 +39,12 @@ #include <linux/slab.h> #include <linux/module.h> /* from BKL pushdown: note that nothing else serializes idr_find() */ /* from BKL pushdown */ DEFINE_MUTEX(drm_global_mutex); EXPORT_SYMBOL(drm_global_mutex); static int drm_open_helper(struct inode *inode, struct file *filp, struct drm_device * dev); struct drm_minor *minor); static int drm_setup(struct drm_device * dev) { Loading Loading @@ -79,29 +79,23 @@ static int drm_setup(struct drm_device * dev) */ int drm_open(struct inode *inode, struct file *filp) { struct drm_device *dev = NULL; int minor_id = iminor(inode); struct drm_device *dev; struct drm_minor *minor; int retcode = 0; int retcode; int need_setup = 0; minor = idr_find(&drm_minors_idr, minor_id); if (!minor) return -ENODEV; if (!(dev = minor->dev)) return -ENODEV; if (drm_device_is_unplugged(dev)) return -ENODEV; minor = drm_minor_acquire(iminor(inode)); if (IS_ERR(minor)) return PTR_ERR(minor); dev = minor->dev; if (!dev->open_count++) need_setup = 1; /* share address_space across all char-devs of a single device */ filp->f_mapping = dev->anon_inode->i_mapping; retcode = drm_open_helper(inode, filp, dev); retcode = drm_open_helper(inode, filp, minor); if (retcode) goto err_undo; if (need_setup) { Loading @@ -113,6 +107,7 @@ int drm_open(struct inode *inode, struct file *filp) err_undo: dev->open_count--; drm_minor_release(minor); return retcode; } EXPORT_SYMBOL(drm_open); Loading @@ -128,33 +123,30 @@ EXPORT_SYMBOL(drm_open); */ int drm_stub_open(struct inode *inode, struct file *filp) { struct drm_device *dev = NULL; struct drm_device *dev; struct drm_minor *minor; int minor_id = iminor(inode); int err = -ENODEV; const struct file_operations *new_fops; DRM_DEBUG("\n"); mutex_lock(&drm_global_mutex); minor = idr_find(&drm_minors_idr, minor_id); if (!minor) goto out; if (!(dev = minor->dev)) goto out; if (drm_device_is_unplugged(dev)) goto out; minor = drm_minor_acquire(iminor(inode)); if (IS_ERR(minor)) goto out_unlock; dev = minor->dev; new_fops = fops_get(dev->driver->fops); if (!new_fops) goto out; goto out_release; replace_fops(filp, new_fops); if (filp->f_op->open) err = filp->f_op->open(inode, filp); out: out_release: drm_minor_release(minor); out_unlock: mutex_unlock(&drm_global_mutex); return err; } Loading @@ -181,16 +173,16 @@ static int drm_cpu_valid(void) * * \param inode device inode. * \param filp file pointer. * \param dev device. * \param minor acquired minor-object. * \return zero on success or a negative number on failure. * * Creates and initializes a drm_file structure for the file private data in \p * filp and add it into the double linked list in \p dev. */ static int drm_open_helper(struct inode *inode, struct file *filp, struct drm_device * dev) struct drm_minor *minor) { int minor_id = iminor(inode); struct drm_device *dev = minor->dev; struct drm_file *priv; int ret; Loading @@ -201,7 +193,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp, if (dev->switch_power_state != DRM_SWITCH_POWER_ON && dev->switch_power_state != DRM_SWITCH_POWER_DYNAMIC_OFF) return -EINVAL; DRM_DEBUG("pid = %d, minor = %d\n", task_pid_nr(current), minor_id); DRM_DEBUG("pid = %d, minor = %d\n", task_pid_nr(current), minor->index); priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) Loading @@ -211,11 +203,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp, priv->filp = filp; priv->uid = current_euid(); priv->pid = get_pid(task_pid(current)); priv->minor = idr_find(&drm_minors_idr, minor_id); if (!priv->minor) { ret = -ENODEV; goto out_put_pid; } priv->minor = minor; /* for compatibility root is always authenticated */ priv->always_authenticated = capable(CAP_SYS_ADMIN); Loading Loading @@ -321,7 +309,6 @@ static int drm_open_helper(struct inode *inode, struct file *filp, drm_prime_destroy_file_private(&priv->prime); if (dev->driver->driver_features & DRIVER_GEM) drm_gem_release(dev, priv); out_put_pid: put_pid(priv->pid); kfree(priv); filp->private_data = NULL; Loading Loading @@ -442,7 +429,8 @@ int drm_lastclose(struct drm_device * dev) int drm_release(struct inode *inode, struct file *filp) { struct drm_file *file_priv = filp->private_data; struct drm_device *dev = file_priv->minor->dev; struct drm_minor *minor = file_priv->minor; struct drm_device *dev = minor->dev; int retcode = 0; mutex_lock(&drm_global_mutex); Loading @@ -458,7 +446,7 @@ int drm_release(struct inode *inode, struct file *filp) DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n", task_pid_nr(current), (long)old_encode_dev(file_priv->minor->device), (long)old_encode_dev(file_priv->minor->kdev->devt), dev->open_count); /* Release any auth tokens that might point to this file_priv, Loading Loading @@ -561,6 +549,8 @@ int drm_release(struct inode *inode, struct file *filp) } mutex_unlock(&drm_global_mutex); drm_minor_release(minor); return retcode; } EXPORT_SYMBOL(drm_release); Loading
drivers/gpu/drm/drm_pci.c +1 −1 Original line number Diff line number Diff line Loading @@ -351,7 +351,7 @@ int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent, drm_pci_agp_destroy(dev); pci_disable_device(pdev); err_free: drm_dev_free(dev); drm_dev_unref(dev); return ret; } EXPORT_SYMBOL(drm_get_pci_dev); Loading
drivers/gpu/drm/drm_platform.c +1 −1 Original line number Diff line number Diff line Loading @@ -64,7 +64,7 @@ static int drm_get_platform_dev(struct platform_device *platdev, return 0; err_free: drm_dev_free(dev); drm_dev_unref(dev); return ret; } Loading
drivers/gpu/drm/drm_stub.c +216 −132 Original line number Diff line number Diff line Loading @@ -72,6 +72,7 @@ module_param_named(vblankoffdelay, drm_vblank_offdelay, int, 0600); module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600); module_param_named(timestamp_monotonic, drm_timestamp_monotonic, int, 0600); static DEFINE_SPINLOCK(drm_minor_lock); struct idr drm_minors_idr; struct class *drm_class; Loading Loading @@ -119,26 +120,6 @@ void drm_ut_debug_printk(unsigned int request_level, } EXPORT_SYMBOL(drm_ut_debug_printk); static int drm_minor_get_id(struct drm_device *dev, int type) { int ret; int base = 0, limit = 63; if (type == DRM_MINOR_CONTROL) { base += 64; limit = base + 63; } else if (type == DRM_MINOR_RENDER) { base += 128; limit = base + 63; } mutex_lock(&dev->struct_mutex); ret = idr_alloc(&drm_minors_idr, NULL, base, limit, GFP_KERNEL); mutex_unlock(&dev->struct_mutex); return ret == -ENOSPC ? -EINVAL : ret; } struct drm_master *drm_master_create(struct drm_minor *minor) { struct drm_master *master; Loading Loading @@ -262,119 +243,183 @@ int drm_dropmaster_ioctl(struct drm_device *dev, void *data, return 0; } /** * drm_get_minor - Allocate and register new DRM minor * @dev: DRM device * @minor: Pointer to where new minor is stored * @type: Type of minor * * Allocate a new minor of the given type and register it. A pointer to the new * minor is returned in @minor. * Caller must hold the global DRM mutex. /* * DRM Minors * A DRM device can provide several char-dev interfaces on the DRM-Major. Each * of them is represented by a drm_minor object. Depending on the capabilities * of the device-driver, different interfaces are registered. * * RETURNS: * 0 on success, negative error code on failure. * Minors can be accessed via dev->$minor_name. This pointer is either * NULL or a valid drm_minor pointer and stays valid as long as the device is * valid. This means, DRM minors have the same life-time as the underlying * device. However, this doesn't mean that the minor is active. Minors are * registered and unregistered dynamically according to device-state. */ static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int type) static struct drm_minor **drm_minor_get_slot(struct drm_device *dev, unsigned int type) { switch (type) { case DRM_MINOR_LEGACY: return &dev->primary; case DRM_MINOR_RENDER: return &dev->render; case DRM_MINOR_CONTROL: return &dev->control; default: return NULL; } } static int drm_minor_alloc(struct drm_device *dev, unsigned int type) { struct drm_minor *minor; minor = kzalloc(sizeof(*minor), GFP_KERNEL); if (!minor) return -ENOMEM; minor->type = type; minor->dev = dev; INIT_LIST_HEAD(&minor->master_list); *drm_minor_get_slot(dev, type) = minor; return 0; } static void drm_minor_free(struct drm_device *dev, unsigned int type) { struct drm_minor **slot; slot = drm_minor_get_slot(dev, type); if (*slot) { kfree(*slot); *slot = NULL; } } static int drm_minor_register(struct drm_device *dev, unsigned int type) { struct drm_minor *new_minor; unsigned long flags; int ret; int minor_id; DRM_DEBUG("\n"); minor_id = drm_minor_get_id(dev, type); new_minor = *drm_minor_get_slot(dev, type); if (!new_minor) return 0; idr_preload(GFP_KERNEL); spin_lock_irqsave(&drm_minor_lock, flags); minor_id = idr_alloc(&drm_minors_idr, NULL, 64 * type, 64 * (type + 1), GFP_NOWAIT); spin_unlock_irqrestore(&drm_minor_lock, flags); idr_preload_end(); if (minor_id < 0) return minor_id; new_minor = kzalloc(sizeof(struct drm_minor), GFP_KERNEL); if (!new_minor) { ret = -ENOMEM; goto err_idr; } new_minor->type = type; new_minor->device = MKDEV(DRM_MAJOR, minor_id); new_minor->dev = dev; new_minor->index = minor_id; INIT_LIST_HEAD(&new_minor->master_list); idr_replace(&drm_minors_idr, new_minor, minor_id); #if defined(CONFIG_DEBUG_FS) ret = drm_debugfs_init(new_minor, minor_id, drm_debugfs_root); if (ret) { DRM_ERROR("DRM: Failed to initialize /sys/kernel/debug/dri.\n"); goto err_mem; goto err_id; } #endif ret = drm_sysfs_device_add(new_minor); if (ret) { printk(KERN_ERR "DRM: Error sysfs_device_add.\n"); DRM_ERROR("DRM: Error sysfs_device_add.\n"); goto err_debugfs; } *minor = new_minor; /* replace NULL with @minor so lookups will succeed from now on */ spin_lock_irqsave(&drm_minor_lock, flags); idr_replace(&drm_minors_idr, new_minor, new_minor->index); spin_unlock_irqrestore(&drm_minor_lock, flags); DRM_DEBUG("new minor assigned %d\n", minor_id); return 0; err_debugfs: #if defined(CONFIG_DEBUG_FS) drm_debugfs_cleanup(new_minor); err_mem: #endif kfree(new_minor); err_idr: err_id: spin_lock_irqsave(&drm_minor_lock, flags); idr_remove(&drm_minors_idr, minor_id); *minor = NULL; spin_unlock_irqrestore(&drm_minor_lock, flags); new_minor->index = 0; return ret; } /** * drm_unplug_minor - Unplug DRM minor * @minor: Minor to unplug * * Unplugs the given DRM minor but keeps the object. So after this returns, * minor->dev is still valid so existing open-files can still access it to get * device information from their drm_file ojects. * If the minor is already unplugged or if @minor is NULL, nothing is done. * The global DRM mutex must be held by the caller. */ static void drm_unplug_minor(struct drm_minor *minor) static void drm_minor_unregister(struct drm_device *dev, unsigned int type) { struct drm_minor *minor; unsigned long flags; minor = *drm_minor_get_slot(dev, type); if (!minor || !minor->kdev) return; #if defined(CONFIG_DEBUG_FS) drm_debugfs_cleanup(minor); #endif spin_lock_irqsave(&drm_minor_lock, flags); idr_remove(&drm_minors_idr, minor->index); spin_unlock_irqrestore(&drm_minor_lock, flags); minor->index = 0; drm_debugfs_cleanup(minor); drm_sysfs_device_remove(minor); idr_remove(&drm_minors_idr, minor->index); } /** * drm_put_minor - Destroy DRM minor * @minor: Minor to destroy * drm_minor_acquire - Acquire a DRM minor * @minor_id: Minor ID of the DRM-minor * * Looks up the given minor-ID and returns the respective DRM-minor object. The * refence-count of the underlying device is increased so you must release this * object with drm_minor_release(). * * This calls drm_unplug_minor() on the given minor and then frees it. Nothing * is done if @minor is NULL. It is fine to call this on already unplugged * minors. * The global DRM mutex must be held by the caller. * As long as you hold this minor, it is guaranteed that the object and the * minor->dev pointer will stay valid! However, the device may get unplugged and * unregistered while you hold the minor. * * Returns: * Pointer to minor-object with increased device-refcount, or PTR_ERR on * failure. */ static void drm_put_minor(struct drm_minor *minor) struct drm_minor *drm_minor_acquire(unsigned int minor_id) { if (!minor) return; struct drm_minor *minor; unsigned long flags; DRM_DEBUG("release secondary minor %d\n", minor->index); spin_lock_irqsave(&drm_minor_lock, flags); minor = idr_find(&drm_minors_idr, minor_id); if (minor) drm_dev_ref(minor->dev); spin_unlock_irqrestore(&drm_minor_lock, flags); drm_unplug_minor(minor); kfree(minor); if (!minor) { return ERR_PTR(-ENODEV); } else if (drm_device_is_unplugged(minor->dev)) { drm_dev_unref(minor->dev); return ERR_PTR(-ENODEV); } return minor; } /** * drm_minor_release - Release DRM minor * @minor: Pointer to DRM minor object * * Release a minor that was previously acquired via drm_minor_acquire(). */ void drm_minor_release(struct drm_minor *minor) { drm_dev_unref(minor->dev); } /** Loading @@ -394,18 +439,16 @@ void drm_put_dev(struct drm_device *dev) } drm_dev_unregister(dev); drm_dev_free(dev); drm_dev_unref(dev); } EXPORT_SYMBOL(drm_put_dev); void drm_unplug_dev(struct drm_device *dev) { /* for a USB device */ if (drm_core_check_feature(dev, DRIVER_MODESET)) drm_unplug_minor(dev->control); if (dev->render) drm_unplug_minor(dev->render); drm_unplug_minor(dev->primary); drm_minor_unregister(dev, DRM_MINOR_LEGACY); drm_minor_unregister(dev, DRM_MINOR_RENDER); drm_minor_unregister(dev, DRM_MINOR_CONTROL); mutex_lock(&drm_global_mutex); Loading Loading @@ -499,6 +542,9 @@ static void drm_fs_inode_free(struct inode *inode) * Call drm_dev_register() to advertice the device to user space and register it * with other core subsystems. * * The initial ref-count of the object is 1. Use drm_dev_ref() and * drm_dev_unref() to take and drop further ref-counts. * * RETURNS: * Pointer to new DRM device, or NULL if out of memory. */ Loading @@ -512,6 +558,7 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver, if (!dev) return NULL; kref_init(&dev->ref); dev->dev = parent; dev->driver = driver; Loading @@ -533,8 +580,24 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver, goto err_free; } if (drm_core_check_feature(dev, DRIVER_MODESET)) { ret = drm_minor_alloc(dev, DRM_MINOR_CONTROL); if (ret) goto err_minors; } if (drm_core_check_feature(dev, DRIVER_RENDER) && drm_rnodes) { ret = drm_minor_alloc(dev, DRM_MINOR_RENDER); if (ret) goto err_minors; } ret = drm_minor_alloc(dev, DRM_MINOR_LEGACY); if (ret) goto err_minors; if (drm_ht_create(&dev->map_hash, 12)) goto err_inode; goto err_minors; ret = drm_ctxbitmap_init(dev); if (ret) { Loading @@ -556,7 +619,10 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver, drm_ctxbitmap_cleanup(dev); err_ht: drm_ht_remove(&dev->map_hash); err_inode: err_minors: drm_minor_free(dev, DRM_MINOR_LEGACY); drm_minor_free(dev, DRM_MINOR_RENDER); drm_minor_free(dev, DRM_MINOR_CONTROL); drm_fs_inode_free(dev->anon_inode); err_free: kfree(dev); Loading @@ -564,21 +630,9 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver, } EXPORT_SYMBOL(drm_dev_alloc); /** * drm_dev_free - Free DRM device * @dev: DRM device to free * * Free a DRM device that has previously been allocated via drm_dev_alloc(). * You must not use kfree() instead or you will leak memory. * * This must not be called once the device got registered. Use drm_put_dev() * instead, which then calls drm_dev_free(). */ void drm_dev_free(struct drm_device *dev) static void drm_dev_release(struct kref *ref) { drm_put_minor(dev->control); drm_put_minor(dev->render); drm_put_minor(dev->primary); struct drm_device *dev = container_of(ref, struct drm_device, ref); if (dev->driver->driver_features & DRIVER_GEM) drm_gem_destroy(dev); Loading @@ -587,10 +641,46 @@ void drm_dev_free(struct drm_device *dev) drm_ht_remove(&dev->map_hash); drm_fs_inode_free(dev->anon_inode); drm_minor_free(dev, DRM_MINOR_LEGACY); drm_minor_free(dev, DRM_MINOR_RENDER); drm_minor_free(dev, DRM_MINOR_CONTROL); kfree(dev->devname); kfree(dev); } EXPORT_SYMBOL(drm_dev_free); /** * drm_dev_ref - Take reference of a DRM device * @dev: device to take reference of or NULL * * This increases the ref-count of @dev by one. You *must* already own a * reference when calling this. Use drm_dev_unref() to drop this reference * again. * * This function never fails. However, this function does not provide *any* * guarantee whether the device is alive or running. It only provides a * reference to the object and the memory associated with it. */ void drm_dev_ref(struct drm_device *dev) { if (dev) kref_get(&dev->ref); } EXPORT_SYMBOL(drm_dev_ref); /** * drm_dev_unref - Drop reference of a DRM device * @dev: device to drop reference of or NULL * * This decreases the ref-count of @dev by one. The device is destroyed if the * ref-count drops to zero. */ void drm_dev_unref(struct drm_device *dev) { if (dev) kref_put(&dev->ref, drm_dev_release); } EXPORT_SYMBOL(drm_dev_unref); /** * drm_dev_register - Register DRM device Loading @@ -611,26 +701,22 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags) mutex_lock(&drm_global_mutex); if (drm_core_check_feature(dev, DRIVER_MODESET)) { ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL); ret = drm_minor_register(dev, DRM_MINOR_CONTROL); if (ret) goto out_unlock; } goto err_minors; if (drm_core_check_feature(dev, DRIVER_RENDER) && drm_rnodes) { ret = drm_get_minor(dev, &dev->render, DRM_MINOR_RENDER); ret = drm_minor_register(dev, DRM_MINOR_RENDER); if (ret) goto err_control_node; } goto err_minors; ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY); ret = drm_minor_register(dev, DRM_MINOR_LEGACY); if (ret) goto err_render_node; goto err_minors; if (dev->driver->load) { ret = dev->driver->load(dev, flags); if (ret) goto err_primary_node; goto err_minors; } /* setup grouping for legacy outputs */ Loading @@ -647,12 +733,10 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags) err_unload: if (dev->driver->unload) dev->driver->unload(dev); err_primary_node: drm_unplug_minor(dev->primary); err_render_node: drm_unplug_minor(dev->render); err_control_node: drm_unplug_minor(dev->control); err_minors: drm_minor_unregister(dev, DRM_MINOR_LEGACY); drm_minor_unregister(dev, DRM_MINOR_RENDER); drm_minor_unregister(dev, DRM_MINOR_CONTROL); out_unlock: mutex_unlock(&drm_global_mutex); return ret; Loading @@ -665,7 +749,7 @@ EXPORT_SYMBOL(drm_dev_register); * * Unregister the DRM device from the system. This does the reverse of * drm_dev_register() but does not deallocate the device. The caller must call * drm_dev_free() to free all resources. * drm_dev_unref() to drop their final reference. */ void drm_dev_unregister(struct drm_device *dev) { Loading @@ -684,8 +768,8 @@ void drm_dev_unregister(struct drm_device *dev) list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head) drm_rmmap(dev, r_list->map); drm_unplug_minor(dev->control); drm_unplug_minor(dev->render); drm_unplug_minor(dev->primary); drm_minor_unregister(dev, DRM_MINOR_LEGACY); drm_minor_unregister(dev, DRM_MINOR_RENDER); drm_minor_unregister(dev, DRM_MINOR_CONTROL); } EXPORT_SYMBOL(drm_dev_unregister);