aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2014-03-16 22:29:29 -0400
committerDave Airlie <airlied@redhat.com>2014-03-16 22:29:29 -0400
commite40d641099213145a034981e646dc2180a488152 (patch)
tree49b892d13877e2ff7bc6cf1875bfc190500d4437 /drivers/gpu
parent28b90a9e7fda90846b5257d7dce6311997c930f1 (diff)
parent0d639883ee26359e1bf38195df1dbca0f879e239 (diff)
Merge branch 'drm-minor' of git://people.freedesktop.org/~dvdhrm/linux into drm-next
This series contains several cleanups for the DRM-minor handling. All but the last one reviewed by Daniel and tested by Thierry. Initially, the series included patches to convert minor-handling to a common base-ID, but have been NACKed by Daniel so I dropped them and only included the main part in the last patch. With this in place, drm_global_mutex is no longer needed for minor-handling (but still for device unregistration..). There are some pending patches that try to remove the global mutex entirely, but they need some more reviews and thus are not included. * 'drm-minor' of git://people.freedesktop.org/~dvdhrm/linux: drm: make minors independent of global lock drm: inline drm_minor_get_id() drm: coding-style fixes in minor handling drm: remove redundant minor->device field drm: remove unneeded #ifdef CONFIG_DEBUGFS drm: rename drm_unplug/get_minor() to drm_minor_register/unregister() drm: move drm_put_minor() to drm_minor_free() drm: allocate minors early drm: add minor-lookup/release helpers drm: provide device-refcount drm: turn DRM_MINOR_* into enum drm: remove unused DRM_MINOR_UNASSIGNED drm: skip redundant minor-lookup in open path drm: group dev-lifetime related members
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/drm_drv.c4
-rw-r--r--drivers/gpu/drm/drm_fops.c70
-rw-r--r--drivers/gpu/drm/drm_pci.c2
-rw-r--r--drivers/gpu/drm/drm_platform.c2
-rw-r--r--drivers/gpu/drm/drm_stub.c348
-rw-r--r--drivers/gpu/drm/drm_usb.c2
-rw-r--r--drivers/gpu/drm/tegra/bus.c2
7 files changed, 252 insertions, 178 deletions
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 345be03c23db..ec651be2f3cb 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -344,7 +344,7 @@ long drm_ioctl(struct file *filp,
344 344
345 DRM_DEBUG("pid=%d, dev=0x%lx, auth=%d, %s\n", 345 DRM_DEBUG("pid=%d, dev=0x%lx, auth=%d, %s\n",
346 task_pid_nr(current), 346 task_pid_nr(current),
347 (long)old_encode_dev(file_priv->minor->device), 347 (long)old_encode_dev(file_priv->minor->kdev->devt),
348 file_priv->authenticated, ioctl->name); 348 file_priv->authenticated, ioctl->name);
349 349
350 /* Do not trust userspace, use our own definition */ 350 /* Do not trust userspace, use our own definition */
@@ -402,7 +402,7 @@ long drm_ioctl(struct file *filp,
402 if (!ioctl) 402 if (!ioctl)
403 DRM_DEBUG("invalid ioctl: pid=%d, dev=0x%lx, auth=%d, cmd=0x%02x, nr=0x%02x\n", 403 DRM_DEBUG("invalid ioctl: pid=%d, dev=0x%lx, auth=%d, cmd=0x%02x, nr=0x%02x\n",
404 task_pid_nr(current), 404 task_pid_nr(current),
405 (long)old_encode_dev(file_priv->minor->device), 405 (long)old_encode_dev(file_priv->minor->kdev->devt),
406 file_priv->authenticated, cmd, nr); 406 file_priv->authenticated, cmd, nr);
407 407
408 if (kdata != stack_kdata) 408 if (kdata != stack_kdata)
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index 7f2af9aca038..8f46fe273ba3 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -39,12 +39,12 @@
39#include <linux/slab.h> 39#include <linux/slab.h>
40#include <linux/module.h> 40#include <linux/module.h>
41 41
42/* from BKL pushdown: note that nothing else serializes idr_find() */ 42/* from BKL pushdown */
43DEFINE_MUTEX(drm_global_mutex); 43DEFINE_MUTEX(drm_global_mutex);
44EXPORT_SYMBOL(drm_global_mutex); 44EXPORT_SYMBOL(drm_global_mutex);
45 45
46static int drm_open_helper(struct inode *inode, struct file *filp, 46static int drm_open_helper(struct inode *inode, struct file *filp,
47 struct drm_device * dev); 47 struct drm_minor *minor);
48 48
49static int drm_setup(struct drm_device * dev) 49static int drm_setup(struct drm_device * dev)
50{ 50{
@@ -79,24 +79,18 @@ static int drm_setup(struct drm_device * dev)
79 */ 79 */
80int drm_open(struct inode *inode, struct file *filp) 80int drm_open(struct inode *inode, struct file *filp)
81{ 81{
82 struct drm_device *dev = NULL; 82 struct drm_device *dev;
83 int minor_id = iminor(inode);
84 struct drm_minor *minor; 83 struct drm_minor *minor;
85 int retcode = 0; 84 int retcode;
86 int need_setup = 0; 85 int need_setup = 0;
87 struct address_space *old_mapping; 86 struct address_space *old_mapping;
88 struct address_space *old_imapping; 87 struct address_space *old_imapping;
89 88
90 minor = idr_find(&drm_minors_idr, minor_id); 89 minor = drm_minor_acquire(iminor(inode));
91 if (!minor) 90 if (IS_ERR(minor))
92 return -ENODEV; 91 return PTR_ERR(minor);
93
94 if (!(dev = minor->dev))
95 return -ENODEV;
96
97 if (drm_device_is_unplugged(dev))
98 return -ENODEV;
99 92
93 dev = minor->dev;
100 if (!dev->open_count++) 94 if (!dev->open_count++)
101 need_setup = 1; 95 need_setup = 1;
102 mutex_lock(&dev->struct_mutex); 96 mutex_lock(&dev->struct_mutex);
@@ -110,7 +104,7 @@ int drm_open(struct inode *inode, struct file *filp)
110 filp->f_mapping = dev->dev_mapping; 104 filp->f_mapping = dev->dev_mapping;
111 mutex_unlock(&dev->struct_mutex); 105 mutex_unlock(&dev->struct_mutex);
112 106
113 retcode = drm_open_helper(inode, filp, dev); 107 retcode = drm_open_helper(inode, filp, minor);
114 if (retcode) 108 if (retcode)
115 goto err_undo; 109 goto err_undo;
116 if (need_setup) { 110 if (need_setup) {
@@ -128,6 +122,7 @@ err_undo:
128 dev->dev_mapping = old_mapping; 122 dev->dev_mapping = old_mapping;
129 mutex_unlock(&dev->struct_mutex); 123 mutex_unlock(&dev->struct_mutex);
130 dev->open_count--; 124 dev->open_count--;
125 drm_minor_release(minor);
131 return retcode; 126 return retcode;
132} 127}
133EXPORT_SYMBOL(drm_open); 128EXPORT_SYMBOL(drm_open);
@@ -143,33 +138,30 @@ EXPORT_SYMBOL(drm_open);
143 */ 138 */
144int drm_stub_open(struct inode *inode, struct file *filp) 139int drm_stub_open(struct inode *inode, struct file *filp)
145{ 140{
146 struct drm_device *dev = NULL; 141 struct drm_device *dev;
147 struct drm_minor *minor; 142 struct drm_minor *minor;
148 int minor_id = iminor(inode);
149 int err = -ENODEV; 143 int err = -ENODEV;
150 const struct file_operations *new_fops; 144 const struct file_operations *new_fops;
151 145
152 DRM_DEBUG("\n"); 146 DRM_DEBUG("\n");
153 147
154 mutex_lock(&drm_global_mutex); 148 mutex_lock(&drm_global_mutex);
155 minor = idr_find(&drm_minors_idr, minor_id); 149 minor = drm_minor_acquire(iminor(inode));
156 if (!minor) 150 if (IS_ERR(minor))
157 goto out; 151 goto out_unlock;
158
159 if (!(dev = minor->dev))
160 goto out;
161
162 if (drm_device_is_unplugged(dev))
163 goto out;
164 152
153 dev = minor->dev;
165 new_fops = fops_get(dev->driver->fops); 154 new_fops = fops_get(dev->driver->fops);
166 if (!new_fops) 155 if (!new_fops)
167 goto out; 156 goto out_release;
168 157
169 replace_fops(filp, new_fops); 158 replace_fops(filp, new_fops);
170 if (filp->f_op->open) 159 if (filp->f_op->open)
171 err = filp->f_op->open(inode, filp); 160 err = filp->f_op->open(inode, filp);
172out: 161
162out_release:
163 drm_minor_release(minor);
164out_unlock:
173 mutex_unlock(&drm_global_mutex); 165 mutex_unlock(&drm_global_mutex);
174 return err; 166 return err;
175} 167}
@@ -196,16 +188,16 @@ static int drm_cpu_valid(void)
196 * 188 *
197 * \param inode device inode. 189 * \param inode device inode.
198 * \param filp file pointer. 190 * \param filp file pointer.
199 * \param dev device. 191 * \param minor acquired minor-object.
200 * \return zero on success or a negative number on failure. 192 * \return zero on success or a negative number on failure.
201 * 193 *
202 * Creates and initializes a drm_file structure for the file private data in \p 194 * Creates and initializes a drm_file structure for the file private data in \p
203 * filp and add it into the double linked list in \p dev. 195 * filp and add it into the double linked list in \p dev.
204 */ 196 */
205static int drm_open_helper(struct inode *inode, struct file *filp, 197static int drm_open_helper(struct inode *inode, struct file *filp,
206 struct drm_device * dev) 198 struct drm_minor *minor)
207{ 199{
208 int minor_id = iminor(inode); 200 struct drm_device *dev = minor->dev;
209 struct drm_file *priv; 201 struct drm_file *priv;
210 int ret; 202 int ret;
211 203
@@ -216,7 +208,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
216 if (dev->switch_power_state != DRM_SWITCH_POWER_ON && dev->switch_power_state != DRM_SWITCH_POWER_DYNAMIC_OFF) 208 if (dev->switch_power_state != DRM_SWITCH_POWER_ON && dev->switch_power_state != DRM_SWITCH_POWER_DYNAMIC_OFF)
217 return -EINVAL; 209 return -EINVAL;
218 210
219 DRM_DEBUG("pid = %d, minor = %d\n", task_pid_nr(current), minor_id); 211 DRM_DEBUG("pid = %d, minor = %d\n", task_pid_nr(current), minor->index);
220 212
221 priv = kzalloc(sizeof(*priv), GFP_KERNEL); 213 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
222 if (!priv) 214 if (!priv)
@@ -226,11 +218,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
226 priv->filp = filp; 218 priv->filp = filp;
227 priv->uid = current_euid(); 219 priv->uid = current_euid();
228 priv->pid = get_pid(task_pid(current)); 220 priv->pid = get_pid(task_pid(current));
229 priv->minor = idr_find(&drm_minors_idr, minor_id); 221 priv->minor = minor;
230 if (!priv->minor) {
231 ret = -ENODEV;
232 goto out_put_pid;
233 }
234 222
235 /* for compatibility root is always authenticated */ 223 /* for compatibility root is always authenticated */
236 priv->always_authenticated = capable(CAP_SYS_ADMIN); 224 priv->always_authenticated = capable(CAP_SYS_ADMIN);
@@ -336,7 +324,6 @@ out_prime_destroy:
336 drm_prime_destroy_file_private(&priv->prime); 324 drm_prime_destroy_file_private(&priv->prime);
337 if (dev->driver->driver_features & DRIVER_GEM) 325 if (dev->driver->driver_features & DRIVER_GEM)
338 drm_gem_release(dev, priv); 326 drm_gem_release(dev, priv);
339out_put_pid:
340 put_pid(priv->pid); 327 put_pid(priv->pid);
341 kfree(priv); 328 kfree(priv);
342 filp->private_data = NULL; 329 filp->private_data = NULL;
@@ -458,7 +445,8 @@ int drm_lastclose(struct drm_device * dev)
458int drm_release(struct inode *inode, struct file *filp) 445int drm_release(struct inode *inode, struct file *filp)
459{ 446{
460 struct drm_file *file_priv = filp->private_data; 447 struct drm_file *file_priv = filp->private_data;
461 struct drm_device *dev = file_priv->minor->dev; 448 struct drm_minor *minor = file_priv->minor;
449 struct drm_device *dev = minor->dev;
462 int retcode = 0; 450 int retcode = 0;
463 451
464 mutex_lock(&drm_global_mutex); 452 mutex_lock(&drm_global_mutex);
@@ -474,7 +462,7 @@ int drm_release(struct inode *inode, struct file *filp)
474 462
475 DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n", 463 DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n",
476 task_pid_nr(current), 464 task_pid_nr(current),
477 (long)old_encode_dev(file_priv->minor->device), 465 (long)old_encode_dev(file_priv->minor->kdev->devt),
478 dev->open_count); 466 dev->open_count);
479 467
480 /* Release any auth tokens that might point to this file_priv, 468 /* Release any auth tokens that might point to this file_priv,
@@ -580,6 +568,8 @@ int drm_release(struct inode *inode, struct file *filp)
580 } 568 }
581 mutex_unlock(&drm_global_mutex); 569 mutex_unlock(&drm_global_mutex);
582 570
571 drm_minor_release(minor);
572
583 return retcode; 573 return retcode;
584} 574}
585EXPORT_SYMBOL(drm_release); 575EXPORT_SYMBOL(drm_release);
diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c
index 5736aaa7e86c..9ded847b05b4 100644
--- a/drivers/gpu/drm/drm_pci.c
+++ b/drivers/gpu/drm/drm_pci.c
@@ -351,7 +351,7 @@ err_agp:
351 drm_pci_agp_destroy(dev); 351 drm_pci_agp_destroy(dev);
352 pci_disable_device(pdev); 352 pci_disable_device(pdev);
353err_free: 353err_free:
354 drm_dev_free(dev); 354 drm_dev_unref(dev);
355 return ret; 355 return ret;
356} 356}
357EXPORT_SYMBOL(drm_get_pci_dev); 357EXPORT_SYMBOL(drm_get_pci_dev);
diff --git a/drivers/gpu/drm/drm_platform.c b/drivers/gpu/drm/drm_platform.c
index 21fc82006b78..319ff5385601 100644
--- a/drivers/gpu/drm/drm_platform.c
+++ b/drivers/gpu/drm/drm_platform.c
@@ -64,7 +64,7 @@ static int drm_get_platform_dev(struct platform_device *platdev,
64 return 0; 64 return 0;
65 65
66err_free: 66err_free:
67 drm_dev_free(dev); 67 drm_dev_unref(dev);
68 return ret; 68 return ret;
69} 69}
70 70
diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c
index 98a33c580ca1..c23eaf6442ff 100644
--- a/drivers/gpu/drm/drm_stub.c
+++ b/drivers/gpu/drm/drm_stub.c
@@ -70,6 +70,7 @@ module_param_named(vblankoffdelay, drm_vblank_offdelay, int, 0600);
70module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600); 70module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600);
71module_param_named(timestamp_monotonic, drm_timestamp_monotonic, int, 0600); 71module_param_named(timestamp_monotonic, drm_timestamp_monotonic, int, 0600);
72 72
73static DEFINE_SPINLOCK(drm_minor_lock);
73struct idr drm_minors_idr; 74struct idr drm_minors_idr;
74 75
75struct class *drm_class; 76struct class *drm_class;
@@ -117,26 +118,6 @@ void drm_ut_debug_printk(unsigned int request_level,
117} 118}
118EXPORT_SYMBOL(drm_ut_debug_printk); 119EXPORT_SYMBOL(drm_ut_debug_printk);
119 120
120static int drm_minor_get_id(struct drm_device *dev, int type)
121{
122 int ret;
123 int base = 0, limit = 63;
124
125 if (type == DRM_MINOR_CONTROL) {
126 base += 64;
127 limit = base + 63;
128 } else if (type == DRM_MINOR_RENDER) {
129 base += 128;
130 limit = base + 63;
131 }
132
133 mutex_lock(&dev->struct_mutex);
134 ret = idr_alloc(&drm_minors_idr, NULL, base, limit, GFP_KERNEL);
135 mutex_unlock(&dev->struct_mutex);
136
137 return ret == -ENOSPC ? -EINVAL : ret;
138}
139
140struct drm_master *drm_master_create(struct drm_minor *minor) 121struct drm_master *drm_master_create(struct drm_minor *minor)
141{ 122{
142 struct drm_master *master; 123 struct drm_master *master;
@@ -260,119 +241,183 @@ int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
260 return 0; 241 return 0;
261} 242}
262 243
263/** 244/*
264 * drm_get_minor - Allocate and register new DRM minor 245 * DRM Minors
265 * @dev: DRM device 246 * A DRM device can provide several char-dev interfaces on the DRM-Major. Each
266 * @minor: Pointer to where new minor is stored 247 * of them is represented by a drm_minor object. Depending on the capabilities
267 * @type: Type of minor 248 * of the device-driver, different interfaces are registered.
268 *
269 * Allocate a new minor of the given type and register it. A pointer to the new
270 * minor is returned in @minor.
271 * Caller must hold the global DRM mutex.
272 * 249 *
273 * RETURNS: 250 * Minors can be accessed via dev->$minor_name. This pointer is either
274 * 0 on success, negative error code on failure. 251 * NULL or a valid drm_minor pointer and stays valid as long as the device is
252 * valid. This means, DRM minors have the same life-time as the underlying
253 * device. However, this doesn't mean that the minor is active. Minors are
254 * registered and unregistered dynamically according to device-state.
275 */ 255 */
276static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, 256
277 int type) 257static struct drm_minor **drm_minor_get_slot(struct drm_device *dev,
258 unsigned int type)
259{
260 switch (type) {
261 case DRM_MINOR_LEGACY:
262 return &dev->primary;
263 case DRM_MINOR_RENDER:
264 return &dev->render;
265 case DRM_MINOR_CONTROL:
266 return &dev->control;
267 default:
268 return NULL;
269 }
270}
271
272static int drm_minor_alloc(struct drm_device *dev, unsigned int type)
273{
274 struct drm_minor *minor;
275
276 minor = kzalloc(sizeof(*minor), GFP_KERNEL);
277 if (!minor)
278 return -ENOMEM;
279
280 minor->type = type;
281 minor->dev = dev;
282 INIT_LIST_HEAD(&minor->master_list);
283
284 *drm_minor_get_slot(dev, type) = minor;
285 return 0;
286}
287
288static void drm_minor_free(struct drm_device *dev, unsigned int type)
289{
290 struct drm_minor **slot;
291
292 slot = drm_minor_get_slot(dev, type);
293 if (*slot) {
294 kfree(*slot);
295 *slot = NULL;
296 }
297}
298
299static int drm_minor_register(struct drm_device *dev, unsigned int type)
278{ 300{
279 struct drm_minor *new_minor; 301 struct drm_minor *new_minor;
302 unsigned long flags;
280 int ret; 303 int ret;
281 int minor_id; 304 int minor_id;
282 305
283 DRM_DEBUG("\n"); 306 DRM_DEBUG("\n");
284 307
285 minor_id = drm_minor_get_id(dev, type); 308 new_minor = *drm_minor_get_slot(dev, type);
309 if (!new_minor)
310 return 0;
311
312 idr_preload(GFP_KERNEL);
313 spin_lock_irqsave(&drm_minor_lock, flags);
314 minor_id = idr_alloc(&drm_minors_idr,
315 NULL,
316 64 * type,
317 64 * (type + 1),
318 GFP_NOWAIT);
319 spin_unlock_irqrestore(&drm_minor_lock, flags);
320 idr_preload_end();
321
286 if (minor_id < 0) 322 if (minor_id < 0)
287 return minor_id; 323 return minor_id;
288 324
289 new_minor = kzalloc(sizeof(struct drm_minor), GFP_KERNEL);
290 if (!new_minor) {
291 ret = -ENOMEM;
292 goto err_idr;
293 }
294
295 new_minor->type = type;
296 new_minor->device = MKDEV(DRM_MAJOR, minor_id);
297 new_minor->dev = dev;
298 new_minor->index = minor_id; 325 new_minor->index = minor_id;
299 INIT_LIST_HEAD(&new_minor->master_list);
300
301 idr_replace(&drm_minors_idr, new_minor, minor_id);
302 326
303#if defined(CONFIG_DEBUG_FS)
304 ret = drm_debugfs_init(new_minor, minor_id, drm_debugfs_root); 327 ret = drm_debugfs_init(new_minor, minor_id, drm_debugfs_root);
305 if (ret) { 328 if (ret) {
306 DRM_ERROR("DRM: Failed to initialize /sys/kernel/debug/dri.\n"); 329 DRM_ERROR("DRM: Failed to initialize /sys/kernel/debug/dri.\n");
307 goto err_mem; 330 goto err_id;
308 } 331 }
309#endif
310 332
311 ret = drm_sysfs_device_add(new_minor); 333 ret = drm_sysfs_device_add(new_minor);
312 if (ret) { 334 if (ret) {
313 printk(KERN_ERR 335 DRM_ERROR("DRM: Error sysfs_device_add.\n");
314 "DRM: Error sysfs_device_add.\n");
315 goto err_debugfs; 336 goto err_debugfs;
316 } 337 }
317 *minor = new_minor; 338
339 /* replace NULL with @minor so lookups will succeed from now on */
340 spin_lock_irqsave(&drm_minor_lock, flags);
341 idr_replace(&drm_minors_idr, new_minor, new_minor->index);
342 spin_unlock_irqrestore(&drm_minor_lock, flags);
318 343
319 DRM_DEBUG("new minor assigned %d\n", minor_id); 344 DRM_DEBUG("new minor assigned %d\n", minor_id);
320 return 0; 345 return 0;
321 346
322
323err_debugfs: 347err_debugfs:
324#if defined(CONFIG_DEBUG_FS)
325 drm_debugfs_cleanup(new_minor); 348 drm_debugfs_cleanup(new_minor);
326err_mem: 349err_id:
327#endif 350 spin_lock_irqsave(&drm_minor_lock, flags);
328 kfree(new_minor);
329err_idr:
330 idr_remove(&drm_minors_idr, minor_id); 351 idr_remove(&drm_minors_idr, minor_id);
331 *minor = NULL; 352 spin_unlock_irqrestore(&drm_minor_lock, flags);
353 new_minor->index = 0;
332 return ret; 354 return ret;
333} 355}
334 356
335/** 357static void drm_minor_unregister(struct drm_device *dev, unsigned int type)
336 * drm_unplug_minor - Unplug DRM minor
337 * @minor: Minor to unplug
338 *
339 * Unplugs the given DRM minor but keeps the object. So after this returns,
340 * minor->dev is still valid so existing open-files can still access it to get
341 * device information from their drm_file ojects.
342 * If the minor is already unplugged or if @minor is NULL, nothing is done.
343 * The global DRM mutex must be held by the caller.
344 */
345static void drm_unplug_minor(struct drm_minor *minor)
346{ 358{
359 struct drm_minor *minor;
360 unsigned long flags;
361
362 minor = *drm_minor_get_slot(dev, type);
347 if (!minor || !minor->kdev) 363 if (!minor || !minor->kdev)
348 return; 364 return;
349 365
350#if defined(CONFIG_DEBUG_FS) 366 spin_lock_irqsave(&drm_minor_lock, flags);
351 drm_debugfs_cleanup(minor); 367 idr_remove(&drm_minors_idr, minor->index);
352#endif 368 spin_unlock_irqrestore(&drm_minor_lock, flags);
369 minor->index = 0;
353 370
371 drm_debugfs_cleanup(minor);
354 drm_sysfs_device_remove(minor); 372 drm_sysfs_device_remove(minor);
355 idr_remove(&drm_minors_idr, minor->index);
356} 373}
357 374
358/** 375/**
359 * drm_put_minor - Destroy DRM minor 376 * drm_minor_acquire - Acquire a DRM minor
360 * @minor: Minor to destroy 377 * @minor_id: Minor ID of the DRM-minor
378 *
379 * Looks up the given minor-ID and returns the respective DRM-minor object. The
380 * refence-count of the underlying device is increased so you must release this
381 * object with drm_minor_release().
382 *
383 * As long as you hold this minor, it is guaranteed that the object and the
384 * minor->dev pointer will stay valid! However, the device may get unplugged and
385 * unregistered while you hold the minor.
361 * 386 *
362 * This calls drm_unplug_minor() on the given minor and then frees it. Nothing 387 * Returns:
363 * is done if @minor is NULL. It is fine to call this on already unplugged 388 * Pointer to minor-object with increased device-refcount, or PTR_ERR on
364 * minors. 389 * failure.
365 * The global DRM mutex must be held by the caller.
366 */ 390 */
367static void drm_put_minor(struct drm_minor *minor) 391struct drm_minor *drm_minor_acquire(unsigned int minor_id)
368{ 392{
369 if (!minor) 393 struct drm_minor *minor;
370 return; 394 unsigned long flags;
395
396 spin_lock_irqsave(&drm_minor_lock, flags);
397 minor = idr_find(&drm_minors_idr, minor_id);
398 if (minor)
399 drm_dev_ref(minor->dev);
400 spin_unlock_irqrestore(&drm_minor_lock, flags);
401
402 if (!minor) {
403 return ERR_PTR(-ENODEV);
404 } else if (drm_device_is_unplugged(minor->dev)) {
405 drm_dev_unref(minor->dev);
406 return ERR_PTR(-ENODEV);
407 }
371 408
372 DRM_DEBUG("release secondary minor %d\n", minor->index); 409 return minor;
410}
373 411
374 drm_unplug_minor(minor); 412/**
375 kfree(minor); 413 * drm_minor_release - Release DRM minor
414 * @minor: Pointer to DRM minor object
415 *
416 * Release a minor that was previously acquired via drm_minor_acquire().
417 */
418void drm_minor_release(struct drm_minor *minor)
419{
420 drm_dev_unref(minor->dev);
376} 421}
377 422
378/** 423/**
@@ -392,18 +437,16 @@ void drm_put_dev(struct drm_device *dev)
392 } 437 }
393 438
394 drm_dev_unregister(dev); 439 drm_dev_unregister(dev);
395 drm_dev_free(dev); 440 drm_dev_unref(dev);
396} 441}
397EXPORT_SYMBOL(drm_put_dev); 442EXPORT_SYMBOL(drm_put_dev);
398 443
399void drm_unplug_dev(struct drm_device *dev) 444void drm_unplug_dev(struct drm_device *dev)
400{ 445{
401 /* for a USB device */ 446 /* for a USB device */
402 if (drm_core_check_feature(dev, DRIVER_MODESET)) 447 drm_minor_unregister(dev, DRM_MINOR_LEGACY);
403 drm_unplug_minor(dev->control); 448 drm_minor_unregister(dev, DRM_MINOR_RENDER);
404 if (dev->render) 449 drm_minor_unregister(dev, DRM_MINOR_CONTROL);
405 drm_unplug_minor(dev->render);
406 drm_unplug_minor(dev->primary);
407 450
408 mutex_lock(&drm_global_mutex); 451 mutex_lock(&drm_global_mutex);
409 452
@@ -425,6 +468,9 @@ EXPORT_SYMBOL(drm_unplug_dev);
425 * Call drm_dev_register() to advertice the device to user space and register it 468 * Call drm_dev_register() to advertice the device to user space and register it
426 * with other core subsystems. 469 * with other core subsystems.
427 * 470 *
471 * The initial ref-count of the object is 1. Use drm_dev_ref() and
472 * drm_dev_unref() to take and drop further ref-counts.
473 *
428 * RETURNS: 474 * RETURNS:
429 * Pointer to new DRM device, or NULL if out of memory. 475 * Pointer to new DRM device, or NULL if out of memory.
430 */ 476 */
@@ -438,6 +484,7 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver,
438 if (!dev) 484 if (!dev)
439 return NULL; 485 return NULL;
440 486
487 kref_init(&dev->ref);
441 dev->dev = parent; 488 dev->dev = parent;
442 dev->driver = driver; 489 dev->driver = driver;
443 490
@@ -452,8 +499,24 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver,
452 mutex_init(&dev->struct_mutex); 499 mutex_init(&dev->struct_mutex);
453 mutex_init(&dev->ctxlist_mutex); 500 mutex_init(&dev->ctxlist_mutex);
454 501
502 if (drm_core_check_feature(dev, DRIVER_MODESET)) {
503 ret = drm_minor_alloc(dev, DRM_MINOR_CONTROL);
504 if (ret)
505 goto err_minors;
506 }
507
508 if (drm_core_check_feature(dev, DRIVER_RENDER) && drm_rnodes) {
509 ret = drm_minor_alloc(dev, DRM_MINOR_RENDER);
510 if (ret)
511 goto err_minors;
512 }
513
514 ret = drm_minor_alloc(dev, DRM_MINOR_LEGACY);
515 if (ret)
516 goto err_minors;
517
455 if (drm_ht_create(&dev->map_hash, 12)) 518 if (drm_ht_create(&dev->map_hash, 12))
456 goto err_free; 519 goto err_minors;
457 520
458 ret = drm_ctxbitmap_init(dev); 521 ret = drm_ctxbitmap_init(dev);
459 if (ret) { 522 if (ret) {
@@ -475,27 +538,18 @@ err_ctxbitmap:
475 drm_ctxbitmap_cleanup(dev); 538 drm_ctxbitmap_cleanup(dev);
476err_ht: 539err_ht:
477 drm_ht_remove(&dev->map_hash); 540 drm_ht_remove(&dev->map_hash);
478err_free: 541err_minors:
542 drm_minor_free(dev, DRM_MINOR_LEGACY);
543 drm_minor_free(dev, DRM_MINOR_RENDER);
544 drm_minor_free(dev, DRM_MINOR_CONTROL);
479 kfree(dev); 545 kfree(dev);
480 return NULL; 546 return NULL;
481} 547}
482EXPORT_SYMBOL(drm_dev_alloc); 548EXPORT_SYMBOL(drm_dev_alloc);
483 549
484/** 550static void drm_dev_release(struct kref *ref)
485 * drm_dev_free - Free DRM device
486 * @dev: DRM device to free
487 *
488 * Free a DRM device that has previously been allocated via drm_dev_alloc().
489 * You must not use kfree() instead or you will leak memory.
490 *
491 * This must not be called once the device got registered. Use drm_put_dev()
492 * instead, which then calls drm_dev_free().
493 */
494void drm_dev_free(struct drm_device *dev)
495{ 551{
496 drm_put_minor(dev->control); 552 struct drm_device *dev = container_of(ref, struct drm_device, ref);
497 drm_put_minor(dev->render);
498 drm_put_minor(dev->primary);
499 553
500 if (dev->driver->driver_features & DRIVER_GEM) 554 if (dev->driver->driver_features & DRIVER_GEM)
501 drm_gem_destroy(dev); 555 drm_gem_destroy(dev);
@@ -503,10 +557,46 @@ void drm_dev_free(struct drm_device *dev)
503 drm_ctxbitmap_cleanup(dev); 557 drm_ctxbitmap_cleanup(dev);
504 drm_ht_remove(&dev->map_hash); 558 drm_ht_remove(&dev->map_hash);
505 559
560 drm_minor_free(dev, DRM_MINOR_LEGACY);
561 drm_minor_free(dev, DRM_MINOR_RENDER);
562 drm_minor_free(dev, DRM_MINOR_CONTROL);
563
506 kfree(dev->devname); 564 kfree(dev->devname);
507 kfree(dev); 565 kfree(dev);
508} 566}
509EXPORT_SYMBOL(drm_dev_free); 567
568/**
569 * drm_dev_ref - Take reference of a DRM device
570 * @dev: device to take reference of or NULL
571 *
572 * This increases the ref-count of @dev by one. You *must* already own a
573 * reference when calling this. Use drm_dev_unref() to drop this reference
574 * again.
575 *
576 * This function never fails. However, this function does not provide *any*
577 * guarantee whether the device is alive or running. It only provides a
578 * reference to the object and the memory associated with it.
579 */
580void drm_dev_ref(struct drm_device *dev)
581{
582 if (dev)
583 kref_get(&dev->ref);
584}
585EXPORT_SYMBOL(drm_dev_ref);
586
587/**
588 * drm_dev_unref - Drop reference of a DRM device
589 * @dev: device to drop reference of or NULL
590 *
591 * This decreases the ref-count of @dev by one. The device is destroyed if the
592 * ref-count drops to zero.
593 */
594void drm_dev_unref(struct drm_device *dev)
595{
596 if (dev)
597 kref_put(&dev->ref, drm_dev_release);
598}
599EXPORT_SYMBOL(drm_dev_unref);
510 600
511/** 601/**
512 * drm_dev_register - Register DRM device 602 * drm_dev_register - Register DRM device
@@ -527,26 +617,22 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags)
527 617
528 mutex_lock(&drm_global_mutex); 618 mutex_lock(&drm_global_mutex);
529 619
530 if (drm_core_check_feature(dev, DRIVER_MODESET)) { 620 ret = drm_minor_register(dev, DRM_MINOR_CONTROL);
531 ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL); 621 if (ret)
532 if (ret) 622 goto err_minors;
533 goto out_unlock;
534 }
535 623
536 if (drm_core_check_feature(dev, DRIVER_RENDER) && drm_rnodes) { 624 ret = drm_minor_register(dev, DRM_MINOR_RENDER);
537 ret = drm_get_minor(dev, &dev->render, DRM_MINOR_RENDER); 625 if (ret)
538 if (ret) 626 goto err_minors;
539 goto err_control_node;
540 }
541 627
542 ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY); 628 ret = drm_minor_register(dev, DRM_MINOR_LEGACY);
543 if (ret) 629 if (ret)
544 goto err_render_node; 630 goto err_minors;
545 631
546 if (dev->driver->load) { 632 if (dev->driver->load) {
547 ret = dev->driver->load(dev, flags); 633 ret = dev->driver->load(dev, flags);
548 if (ret) 634 if (ret)
549 goto err_primary_node; 635 goto err_minors;
550 } 636 }
551 637
552 /* setup grouping for legacy outputs */ 638 /* setup grouping for legacy outputs */
@@ -563,12 +649,10 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags)
563err_unload: 649err_unload:
564 if (dev->driver->unload) 650 if (dev->driver->unload)
565 dev->driver->unload(dev); 651 dev->driver->unload(dev);
566err_primary_node: 652err_minors:
567 drm_unplug_minor(dev->primary); 653 drm_minor_unregister(dev, DRM_MINOR_LEGACY);
568err_render_node: 654 drm_minor_unregister(dev, DRM_MINOR_RENDER);
569 drm_unplug_minor(dev->render); 655 drm_minor_unregister(dev, DRM_MINOR_CONTROL);
570err_control_node:
571 drm_unplug_minor(dev->control);
572out_unlock: 656out_unlock:
573 mutex_unlock(&drm_global_mutex); 657 mutex_unlock(&drm_global_mutex);
574 return ret; 658 return ret;
@@ -581,7 +665,7 @@ EXPORT_SYMBOL(drm_dev_register);
581 * 665 *
582 * Unregister the DRM device from the system. This does the reverse of 666 * Unregister the DRM device from the system. This does the reverse of
583 * drm_dev_register() but does not deallocate the device. The caller must call 667 * drm_dev_register() but does not deallocate the device. The caller must call
584 * drm_dev_free() to free all resources. 668 * drm_dev_unref() to drop their final reference.
585 */ 669 */
586void drm_dev_unregister(struct drm_device *dev) 670void drm_dev_unregister(struct drm_device *dev)
587{ 671{
@@ -600,8 +684,8 @@ void drm_dev_unregister(struct drm_device *dev)
600 list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head) 684 list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head)
601 drm_rmmap(dev, r_list->map); 685 drm_rmmap(dev, r_list->map);
602 686
603 drm_unplug_minor(dev->control); 687 drm_minor_unregister(dev, DRM_MINOR_LEGACY);
604 drm_unplug_minor(dev->render); 688 drm_minor_unregister(dev, DRM_MINOR_RENDER);
605 drm_unplug_minor(dev->primary); 689 drm_minor_unregister(dev, DRM_MINOR_CONTROL);
606} 690}
607EXPORT_SYMBOL(drm_dev_unregister); 691EXPORT_SYMBOL(drm_dev_unregister);
diff --git a/drivers/gpu/drm/drm_usb.c b/drivers/gpu/drm/drm_usb.c
index 0f8cb1ae7607..c3406aad2944 100644
--- a/drivers/gpu/drm/drm_usb.c
+++ b/drivers/gpu/drm/drm_usb.c
@@ -30,7 +30,7 @@ int drm_get_usb_dev(struct usb_interface *interface,
30 return 0; 30 return 0;
31 31
32err_free: 32err_free:
33 drm_dev_free(dev); 33 drm_dev_unref(dev);
34 return ret; 34 return ret;
35 35
36} 36}
diff --git a/drivers/gpu/drm/tegra/bus.c b/drivers/gpu/drm/tegra/bus.c
index e38e5967d77b..71cef5c13dc8 100644
--- a/drivers/gpu/drm/tegra/bus.c
+++ b/drivers/gpu/drm/tegra/bus.c
@@ -63,7 +63,7 @@ int drm_host1x_init(struct drm_driver *driver, struct host1x_device *device)
63 return 0; 63 return 0;
64 64
65err_free: 65err_free:
66 drm_dev_free(drm); 66 drm_dev_unref(drm);
67 return ret; 67 return ret;
68} 68}
69 69