diff options
author | Dave Airlie <airlied@redhat.com> | 2008-11-27 23:22:24 -0500 |
---|---|---|
committer | Dave Airlie <airlied@linux.ie> | 2008-12-29 02:47:22 -0500 |
commit | 7c1c2871a6a3a114853ec6836e9035ac1c0c7f7a (patch) | |
tree | 1b5debcc86ff20bd5e11b42ea5c52da42214e376 /drivers/gpu/drm/drm_fops.c | |
parent | e7f7ab45ebcb54fd5f814ea15ea079e079662f67 (diff) |
drm: move to kref per-master structures.
This is step one towards having multiple masters sharing a drm
device in order to get fast-user-switching to work.
It splits out the information associated with the drm master
into a separate kref counted structure, and allocates this when
a master opens the device node. It also allows the current master
to abdicate (say while VT switched), and a new master to take over
the hardware.
It moves the Intel and radeon drivers to using the sarea from
within the new master structures.
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/drm_fops.c')
-rw-r--r-- | drivers/gpu/drm/drm_fops.c | 201 |
1 files changed, 124 insertions, 77 deletions
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index 78eeed5caaff..f2285237df49 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c | |||
@@ -44,10 +44,8 @@ static int drm_open_helper(struct inode *inode, struct file *filp, | |||
44 | 44 | ||
45 | static int drm_setup(struct drm_device * dev) | 45 | static int drm_setup(struct drm_device * dev) |
46 | { | 46 | { |
47 | drm_local_map_t *map; | ||
48 | int i; | 47 | int i; |
49 | int ret; | 48 | int ret; |
50 | u32 sareapage; | ||
51 | 49 | ||
52 | if (dev->driver->firstopen) { | 50 | if (dev->driver->firstopen) { |
53 | ret = dev->driver->firstopen(dev); | 51 | ret = dev->driver->firstopen(dev); |
@@ -55,14 +53,6 @@ static int drm_setup(struct drm_device * dev) | |||
55 | return ret; | 53 | return ret; |
56 | } | 54 | } |
57 | 55 | ||
58 | dev->magicfree.next = NULL; | ||
59 | |||
60 | /* prebuild the SAREA */ | ||
61 | sareapage = max_t(unsigned, SAREA_MAX, PAGE_SIZE); | ||
62 | i = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK, &map); | ||
63 | if (i != 0) | ||
64 | return i; | ||
65 | |||
66 | atomic_set(&dev->ioctl_count, 0); | 56 | atomic_set(&dev->ioctl_count, 0); |
67 | atomic_set(&dev->vma_count, 0); | 57 | atomic_set(&dev->vma_count, 0); |
68 | dev->buf_use = 0; | 58 | dev->buf_use = 0; |
@@ -77,16 +67,12 @@ static int drm_setup(struct drm_device * dev) | |||
77 | for (i = 0; i < ARRAY_SIZE(dev->counts); i++) | 67 | for (i = 0; i < ARRAY_SIZE(dev->counts); i++) |
78 | atomic_set(&dev->counts[i], 0); | 68 | atomic_set(&dev->counts[i], 0); |
79 | 69 | ||
80 | drm_ht_create(&dev->magiclist, DRM_MAGIC_HASH_ORDER); | ||
81 | INIT_LIST_HEAD(&dev->magicfree); | ||
82 | |||
83 | dev->sigdata.lock = NULL; | 70 | dev->sigdata.lock = NULL; |
84 | init_waitqueue_head(&dev->lock.lock_queue); | 71 | |
85 | dev->queue_count = 0; | 72 | dev->queue_count = 0; |
86 | dev->queue_reserved = 0; | 73 | dev->queue_reserved = 0; |
87 | dev->queue_slots = 0; | 74 | dev->queue_slots = 0; |
88 | dev->queuelist = NULL; | 75 | dev->queuelist = NULL; |
89 | dev->irq_enabled = 0; | ||
90 | dev->context_flag = 0; | 76 | dev->context_flag = 0; |
91 | dev->interrupt_flag = 0; | 77 | dev->interrupt_flag = 0; |
92 | dev->dma_flag = 0; | 78 | dev->dma_flag = 0; |
@@ -265,10 +251,42 @@ static int drm_open_helper(struct inode *inode, struct file *filp, | |||
265 | goto out_free; | 251 | goto out_free; |
266 | } | 252 | } |
267 | 253 | ||
254 | |||
255 | /* if there is no current master make this fd it */ | ||
268 | mutex_lock(&dev->struct_mutex); | 256 | mutex_lock(&dev->struct_mutex); |
269 | if (list_empty(&dev->filelist)) | 257 | if (!priv->minor->master) { |
270 | priv->master = 1; | 258 | /* create a new master */ |
259 | priv->minor->master = drm_master_create(priv->minor); | ||
260 | if (!priv->minor->master) { | ||
261 | ret = -ENOMEM; | ||
262 | goto out_free; | ||
263 | } | ||
264 | |||
265 | priv->is_master = 1; | ||
266 | /* take another reference for the copy in the local file priv */ | ||
267 | priv->master = drm_master_get(priv->minor->master); | ||
268 | |||
269 | priv->authenticated = 1; | ||
270 | |||
271 | mutex_unlock(&dev->struct_mutex); | ||
272 | if (dev->driver->master_create) { | ||
273 | ret = dev->driver->master_create(dev, priv->master); | ||
274 | if (ret) { | ||
275 | mutex_lock(&dev->struct_mutex); | ||
276 | /* drop both references if this fails */ | ||
277 | drm_master_put(&priv->minor->master); | ||
278 | drm_master_put(&priv->master); | ||
279 | mutex_unlock(&dev->struct_mutex); | ||
280 | goto out_free; | ||
281 | } | ||
282 | } | ||
283 | } else { | ||
284 | /* get a reference to the master */ | ||
285 | priv->master = drm_master_get(priv->minor->master); | ||
286 | mutex_unlock(&dev->struct_mutex); | ||
287 | } | ||
271 | 288 | ||
289 | mutex_lock(&dev->struct_mutex); | ||
272 | list_add(&priv->lhead, &dev->filelist); | 290 | list_add(&priv->lhead, &dev->filelist); |
273 | mutex_unlock(&dev->struct_mutex); | 291 | mutex_unlock(&dev->struct_mutex); |
274 | 292 | ||
@@ -314,6 +332,74 @@ int drm_fasync(int fd, struct file *filp, int on) | |||
314 | } | 332 | } |
315 | EXPORT_SYMBOL(drm_fasync); | 333 | EXPORT_SYMBOL(drm_fasync); |
316 | 334 | ||
335 | /* | ||
336 | * Reclaim locked buffers; note that this may be a bad idea if the current | ||
337 | * context doesn't have the hw lock... | ||
338 | */ | ||
339 | static void drm_reclaim_locked_buffers(struct drm_device *dev, struct file *f) | ||
340 | { | ||
341 | struct drm_file *file_priv = f->private_data; | ||
342 | |||
343 | if (drm_i_have_hw_lock(dev, file_priv)) { | ||
344 | dev->driver->reclaim_buffers_locked(dev, file_priv); | ||
345 | } else { | ||
346 | unsigned long _end = jiffies + 3 * DRM_HZ; | ||
347 | int locked = 0; | ||
348 | |||
349 | drm_idlelock_take(&file_priv->master->lock); | ||
350 | |||
351 | /* | ||
352 | * Wait for a while. | ||
353 | */ | ||
354 | do { | ||
355 | spin_lock_bh(&file_priv->master->lock.spinlock); | ||
356 | locked = file_priv->master->lock.idle_has_lock; | ||
357 | spin_unlock_bh(&file_priv->master->lock.spinlock); | ||
358 | if (locked) | ||
359 | break; | ||
360 | schedule(); | ||
361 | } while (!time_after_eq(jiffies, _end)); | ||
362 | |||
363 | if (!locked) { | ||
364 | DRM_ERROR("reclaim_buffers_locked() deadlock. Please rework this\n" | ||
365 | "\tdriver to use reclaim_buffers_idlelocked() instead.\n" | ||
366 | "\tI will go on reclaiming the buffers anyway.\n"); | ||
367 | } | ||
368 | |||
369 | dev->driver->reclaim_buffers_locked(dev, file_priv); | ||
370 | drm_idlelock_release(&file_priv->master->lock); | ||
371 | } | ||
372 | } | ||
373 | |||
374 | static void drm_master_release(struct drm_device *dev, struct file *filp) | ||
375 | { | ||
376 | struct drm_file *file_priv = filp->private_data; | ||
377 | |||
378 | if (dev->driver->reclaim_buffers_locked && | ||
379 | file_priv->master->lock.hw_lock) | ||
380 | drm_reclaim_locked_buffers(dev, filp); | ||
381 | |||
382 | if (dev->driver->reclaim_buffers_idlelocked && | ||
383 | file_priv->master->lock.hw_lock) { | ||
384 | drm_idlelock_take(&file_priv->master->lock); | ||
385 | dev->driver->reclaim_buffers_idlelocked(dev, file_priv); | ||
386 | drm_idlelock_release(&file_priv->master->lock); | ||
387 | } | ||
388 | |||
389 | |||
390 | if (drm_i_have_hw_lock(dev, file_priv)) { | ||
391 | DRM_DEBUG("File %p released, freeing lock for context %d\n", | ||
392 | filp, _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock)); | ||
393 | drm_lock_free(&file_priv->master->lock, | ||
394 | _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock)); | ||
395 | } | ||
396 | |||
397 | if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) && | ||
398 | !dev->driver->reclaim_buffers_locked) { | ||
399 | dev->driver->reclaim_buffers(dev, file_priv); | ||
400 | } | ||
401 | } | ||
402 | |||
317 | /** | 403 | /** |
318 | * Release file. | 404 | * Release file. |
319 | * | 405 | * |
@@ -348,60 +434,9 @@ int drm_release(struct inode *inode, struct file *filp) | |||
348 | (long)old_encode_dev(file_priv->minor->device), | 434 | (long)old_encode_dev(file_priv->minor->device), |
349 | dev->open_count); | 435 | dev->open_count); |
350 | 436 | ||
351 | if (dev->driver->reclaim_buffers_locked && dev->lock.hw_lock) { | 437 | /* if the master has gone away we can't do anything with the lock */ |
352 | if (drm_i_have_hw_lock(dev, file_priv)) { | 438 | if (file_priv->minor->master) |
353 | dev->driver->reclaim_buffers_locked(dev, file_priv); | 439 | drm_master_release(dev, filp); |
354 | } else { | ||
355 | unsigned long endtime = jiffies + 3 * DRM_HZ; | ||
356 | int locked = 0; | ||
357 | |||
358 | drm_idlelock_take(&dev->lock); | ||
359 | |||
360 | /* | ||
361 | * Wait for a while. | ||
362 | */ | ||
363 | |||
364 | do{ | ||
365 | spin_lock_bh(&dev->lock.spinlock); | ||
366 | locked = dev->lock.idle_has_lock; | ||
367 | spin_unlock_bh(&dev->lock.spinlock); | ||
368 | if (locked) | ||
369 | break; | ||
370 | schedule(); | ||
371 | } while (!time_after_eq(jiffies, endtime)); | ||
372 | |||
373 | if (!locked) { | ||
374 | DRM_ERROR("reclaim_buffers_locked() deadlock. Please rework this\n" | ||
375 | "\tdriver to use reclaim_buffers_idlelocked() instead.\n" | ||
376 | "\tI will go on reclaiming the buffers anyway.\n"); | ||
377 | } | ||
378 | |||
379 | dev->driver->reclaim_buffers_locked(dev, file_priv); | ||
380 | drm_idlelock_release(&dev->lock); | ||
381 | } | ||
382 | } | ||
383 | |||
384 | if (dev->driver->reclaim_buffers_idlelocked && dev->lock.hw_lock) { | ||
385 | |||
386 | drm_idlelock_take(&dev->lock); | ||
387 | dev->driver->reclaim_buffers_idlelocked(dev, file_priv); | ||
388 | drm_idlelock_release(&dev->lock); | ||
389 | |||
390 | } | ||
391 | |||
392 | if (drm_i_have_hw_lock(dev, file_priv)) { | ||
393 | DRM_DEBUG("File %p released, freeing lock for context %d\n", | ||
394 | filp, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); | ||
395 | |||
396 | drm_lock_free(&dev->lock, | ||
397 | _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); | ||
398 | } | ||
399 | |||
400 | |||
401 | if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) && | ||
402 | !dev->driver->reclaim_buffers_locked) { | ||
403 | dev->driver->reclaim_buffers(dev, file_priv); | ||
404 | } | ||
405 | 440 | ||
406 | if (dev->driver->driver_features & DRIVER_GEM) | 441 | if (dev->driver->driver_features & DRIVER_GEM) |
407 | drm_gem_release(dev, file_priv); | 442 | drm_gem_release(dev, file_priv); |
@@ -428,12 +463,24 @@ int drm_release(struct inode *inode, struct file *filp) | |||
428 | mutex_unlock(&dev->ctxlist_mutex); | 463 | mutex_unlock(&dev->ctxlist_mutex); |
429 | 464 | ||
430 | mutex_lock(&dev->struct_mutex); | 465 | mutex_lock(&dev->struct_mutex); |
431 | if (file_priv->remove_auth_on_close == 1) { | 466 | |
467 | if (file_priv->is_master) { | ||
432 | struct drm_file *temp; | 468 | struct drm_file *temp; |
469 | list_for_each_entry(temp, &dev->filelist, lhead) { | ||
470 | if ((temp->master == file_priv->master) && | ||
471 | (temp != file_priv)) | ||
472 | temp->authenticated = 0; | ||
473 | } | ||
433 | 474 | ||
434 | list_for_each_entry(temp, &dev->filelist, lhead) | 475 | if (file_priv->minor->master == file_priv->master) { |
435 | temp->authenticated = 0; | 476 | /* drop the reference held my the minor */ |
477 | drm_master_put(&file_priv->minor->master); | ||
478 | } | ||
436 | } | 479 | } |
480 | |||
481 | /* drop the reference held my the file priv */ | ||
482 | drm_master_put(&file_priv->master); | ||
483 | file_priv->is_master = 0; | ||
437 | list_del(&file_priv->lhead); | 484 | list_del(&file_priv->lhead); |
438 | mutex_unlock(&dev->struct_mutex); | 485 | mutex_unlock(&dev->struct_mutex); |
439 | 486 | ||
@@ -448,9 +495,9 @@ int drm_release(struct inode *inode, struct file *filp) | |||
448 | atomic_inc(&dev->counts[_DRM_STAT_CLOSES]); | 495 | atomic_inc(&dev->counts[_DRM_STAT_CLOSES]); |
449 | spin_lock(&dev->count_lock); | 496 | spin_lock(&dev->count_lock); |
450 | if (!--dev->open_count) { | 497 | if (!--dev->open_count) { |
451 | if (atomic_read(&dev->ioctl_count) || dev->blocked) { | 498 | if (atomic_read(&dev->ioctl_count)) { |
452 | DRM_ERROR("Device busy: %d %d\n", | 499 | DRM_ERROR("Device busy: %d\n", |
453 | atomic_read(&dev->ioctl_count), dev->blocked); | 500 | atomic_read(&dev->ioctl_count)); |
454 | spin_unlock(&dev->count_lock); | 501 | spin_unlock(&dev->count_lock); |
455 | unlock_kernel(); | 502 | unlock_kernel(); |
456 | return -EBUSY; | 503 | return -EBUSY; |