diff options
author | Dave Airlie <airlied@redhat.com> | 2014-03-16 22:29:29 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2014-03-16 22:29:29 -0400 |
commit | e40d641099213145a034981e646dc2180a488152 (patch) | |
tree | 49b892d13877e2ff7bc6cf1875bfc190500d4437 /drivers/gpu | |
parent | 28b90a9e7fda90846b5257d7dce6311997c930f1 (diff) | |
parent | 0d639883ee26359e1bf38195df1dbca0f879e239 (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.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_fops.c | 70 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_pci.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_platform.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_stub.c | 348 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_usb.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/bus.c | 2 |
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 */ |
43 | DEFINE_MUTEX(drm_global_mutex); | 43 | DEFINE_MUTEX(drm_global_mutex); |
44 | EXPORT_SYMBOL(drm_global_mutex); | 44 | EXPORT_SYMBOL(drm_global_mutex); |
45 | 45 | ||
46 | static int drm_open_helper(struct inode *inode, struct file *filp, | 46 | static int drm_open_helper(struct inode *inode, struct file *filp, |
47 | struct drm_device * dev); | 47 | struct drm_minor *minor); |
48 | 48 | ||
49 | static int drm_setup(struct drm_device * dev) | 49 | static int drm_setup(struct drm_device * dev) |
50 | { | 50 | { |
@@ -79,24 +79,18 @@ static int drm_setup(struct drm_device * dev) | |||
79 | */ | 79 | */ |
80 | int drm_open(struct inode *inode, struct file *filp) | 80 | int 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 | } |
133 | EXPORT_SYMBOL(drm_open); | 128 | EXPORT_SYMBOL(drm_open); |
@@ -143,33 +138,30 @@ EXPORT_SYMBOL(drm_open); | |||
143 | */ | 138 | */ |
144 | int drm_stub_open(struct inode *inode, struct file *filp) | 139 | int 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); |
172 | out: | 161 | |
162 | out_release: | ||
163 | drm_minor_release(minor); | ||
164 | out_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 | */ |
205 | static int drm_open_helper(struct inode *inode, struct file *filp, | 197 | static 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); |
339 | out_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) | |||
458 | int drm_release(struct inode *inode, struct file *filp) | 445 | int 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 | } |
585 | EXPORT_SYMBOL(drm_release); | 575 | EXPORT_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); |
353 | err_free: | 353 | err_free: |
354 | drm_dev_free(dev); | 354 | drm_dev_unref(dev); |
355 | return ret; | 355 | return ret; |
356 | } | 356 | } |
357 | EXPORT_SYMBOL(drm_get_pci_dev); | 357 | EXPORT_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 | ||
66 | err_free: | 66 | err_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); | |||
70 | module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600); | 70 | module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600); |
71 | module_param_named(timestamp_monotonic, drm_timestamp_monotonic, int, 0600); | 71 | module_param_named(timestamp_monotonic, drm_timestamp_monotonic, int, 0600); |
72 | 72 | ||
73 | static DEFINE_SPINLOCK(drm_minor_lock); | ||
73 | struct idr drm_minors_idr; | 74 | struct idr drm_minors_idr; |
74 | 75 | ||
75 | struct class *drm_class; | 76 | struct class *drm_class; |
@@ -117,26 +118,6 @@ void drm_ut_debug_printk(unsigned int request_level, | |||
117 | } | 118 | } |
118 | EXPORT_SYMBOL(drm_ut_debug_printk); | 119 | EXPORT_SYMBOL(drm_ut_debug_printk); |
119 | 120 | ||
120 | static 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 | |||
140 | struct drm_master *drm_master_create(struct drm_minor *minor) | 121 | struct 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 | */ |
276 | static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, | 256 | |
277 | int type) | 257 | static 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 | |||
272 | static 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 | |||
288 | static 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 | |||
299 | static 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 | |||
323 | err_debugfs: | 347 | err_debugfs: |
324 | #if defined(CONFIG_DEBUG_FS) | ||
325 | drm_debugfs_cleanup(new_minor); | 348 | drm_debugfs_cleanup(new_minor); |
326 | err_mem: | 349 | err_id: |
327 | #endif | 350 | spin_lock_irqsave(&drm_minor_lock, flags); |
328 | kfree(new_minor); | ||
329 | err_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 | /** | 357 | static 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 | */ | ||
345 | static 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 | */ |
367 | static void drm_put_minor(struct drm_minor *minor) | 391 | struct 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 | */ | ||
418 | void 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 | } |
397 | EXPORT_SYMBOL(drm_put_dev); | 442 | EXPORT_SYMBOL(drm_put_dev); |
398 | 443 | ||
399 | void drm_unplug_dev(struct drm_device *dev) | 444 | void 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); |
476 | err_ht: | 539 | err_ht: |
477 | drm_ht_remove(&dev->map_hash); | 540 | drm_ht_remove(&dev->map_hash); |
478 | err_free: | 541 | err_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 | } |
482 | EXPORT_SYMBOL(drm_dev_alloc); | 548 | EXPORT_SYMBOL(drm_dev_alloc); |
483 | 549 | ||
484 | /** | 550 | static 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 | */ | ||
494 | void 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 | } |
509 | EXPORT_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 | */ | ||
580 | void drm_dev_ref(struct drm_device *dev) | ||
581 | { | ||
582 | if (dev) | ||
583 | kref_get(&dev->ref); | ||
584 | } | ||
585 | EXPORT_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 | */ | ||
594 | void drm_dev_unref(struct drm_device *dev) | ||
595 | { | ||
596 | if (dev) | ||
597 | kref_put(&dev->ref, drm_dev_release); | ||
598 | } | ||
599 | EXPORT_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) | |||
563 | err_unload: | 649 | err_unload: |
564 | if (dev->driver->unload) | 650 | if (dev->driver->unload) |
565 | dev->driver->unload(dev); | 651 | dev->driver->unload(dev); |
566 | err_primary_node: | 652 | err_minors: |
567 | drm_unplug_minor(dev->primary); | 653 | drm_minor_unregister(dev, DRM_MINOR_LEGACY); |
568 | err_render_node: | 654 | drm_minor_unregister(dev, DRM_MINOR_RENDER); |
569 | drm_unplug_minor(dev->render); | 655 | drm_minor_unregister(dev, DRM_MINOR_CONTROL); |
570 | err_control_node: | ||
571 | drm_unplug_minor(dev->control); | ||
572 | out_unlock: | 656 | out_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 | */ |
586 | void drm_dev_unregister(struct drm_device *dev) | 670 | void 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 | } |
607 | EXPORT_SYMBOL(drm_dev_unregister); | 691 | EXPORT_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 | ||
32 | err_free: | 32 | err_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 | ||
65 | err_free: | 65 | err_free: |
66 | drm_dev_free(drm); | 66 | drm_dev_unref(drm); |
67 | return ret; | 67 | return ret; |
68 | } | 68 | } |
69 | 69 | ||