1/** 2 * \file drm_fops.c 3 * File operations for DRM 4 * 5 * \author Rickard E. (Rik) Faith <faith@valinux.com> 6 * \author Daryll Strauss <daryll@valinux.com> 7 * \author Gareth Hughes <gareth@valinux.com> 8 */ 9 10/* 11 * Created: Mon Jan 4 08:58:31 1999 by faith@valinux.com 12 * 13 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. 14 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. 15 * All Rights Reserved. 16 * 17 * Permission is hereby granted, free of charge, to any person obtaining a 18 * copy of this software and associated documentation files (the "Software"), 19 * to deal in the Software without restriction, including without limitation 20 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 21 * and/or sell copies of the Software, and to permit persons to whom the 22 * Software is furnished to do so, subject to the following conditions: 23 * 24 * The above copyright notice and this permission notice (including the next 25 * paragraph) shall be included in all copies or substantial portions of the 26 * Software. 27 * 28 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 29 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 30 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 31 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 32 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 33 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 34 * OTHER DEALINGS IN THE SOFTWARE. 35 */ 36 37#include "drmP.h" 38#include <linux/poll.h> 39#include <linux/slab.h> 40#include <linux/smp_lock.h> 41 42/* from BKL pushdown: note that nothing else serializes idr_find() */ 43DEFINE_MUTEX(drm_global_mutex); 44EXPORT_SYMBOL(drm_global_mutex); 45 46static int drm_open_helper(struct inode *inode, struct file *filp, 47 struct drm_device * dev); 48 49static int drm_setup(struct drm_device * dev) 50{ 51 int i; 52 int ret; 53 54 if (dev->driver->firstopen) { 55 ret = dev->driver->firstopen(dev); 56 if (ret != 0) 57 return ret; 58 } 59 60 atomic_set(&dev->ioctl_count, 0); 61 atomic_set(&dev->vma_count, 0); 62 63 if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) && 64 !drm_core_check_feature(dev, DRIVER_MODESET)) { 65 dev->buf_use = 0; 66 atomic_set(&dev->buf_alloc, 0); 67 68 i = drm_dma_setup(dev); 69 if (i < 0) 70 return i; 71 } 72 73 for (i = 0; i < ARRAY_SIZE(dev->counts); i++) 74 atomic_set(&dev->counts[i], 0); 75 76 dev->sigdata.lock = NULL; 77 78 dev->queue_count = 0; 79 dev->queue_reserved = 0; 80 dev->queue_slots = 0; 81 dev->queuelist = NULL; 82 dev->context_flag = 0; 83 dev->interrupt_flag = 0; 84 dev->dma_flag = 0; 85 dev->last_context = 0; 86 dev->last_switch = 0; 87 dev->last_checked = 0; 88 init_waitqueue_head(&dev->context_wait); 89 dev->if_version = 0; 90 91 dev->ctx_start = 0; 92 dev->lck_start = 0; 93 94 dev->buf_async = NULL; 95 init_waitqueue_head(&dev->buf_readers); 96 init_waitqueue_head(&dev->buf_writers); 97 98 DRM_DEBUG("\n"); 99 100 /* 101 * The kernel's context could be created here, but is now created 102 * in drm_dma_enqueue. This is more resource-efficient for 103 * hardware that does not do DMA, but may mean that 104 * drm_select_queue fails between the time the interrupt is 105 * initialized and the time the queues are initialized. 106 */ 107 108 return 0; 109} 110 111/** 112 * Open file. 113 * 114 * \param inode device inode 115 * \param filp file pointer. 116 * \return zero on success or a negative number on failure. 117 * 118 * Searches the DRM device with the same minor number, calls open_helper(), and 119 * increments the device open count. If the open count was previous at zero, 120 * i.e., it's the first that the device is open, then calls setup(). 121 */ 122int drm_open(struct inode *inode, struct file *filp) 123{ 124 struct drm_device *dev = NULL; 125 int minor_id = iminor(inode); 126 struct drm_minor *minor; 127 int retcode = 0; 128 129 minor = idr_find(&drm_minors_idr, minor_id); 130 if (!minor) 131 return -ENODEV; 132 133 if (!(dev = minor->dev)) 134 return -ENODEV; 135 136 retcode = drm_open_helper(inode, filp, dev); 137 if (!retcode) { 138 atomic_inc(&dev->counts[_DRM_STAT_OPENS]); 139 if (!dev->open_count++) 140 retcode = drm_setup(dev); 141 } 142 if (!retcode) { 143 mutex_lock(&dev->struct_mutex); 144 if (minor->type == DRM_MINOR_LEGACY) { 145 if (dev->dev_mapping == NULL) 146 dev->dev_mapping = inode->i_mapping; 147 else if (dev->dev_mapping != inode->i_mapping) 148 retcode = -ENODEV; 149 } 150 mutex_unlock(&dev->struct_mutex); 151 } 152 153 return retcode; 154} 155EXPORT_SYMBOL(drm_open); 156 157/** 158 * File \c open operation. 159 * 160 * \param inode device inode. 161 * \param filp file pointer. 162 * 163 * Puts the dev->fops corresponding to the device minor number into 164 * \p filp, call the \c open method, and restore the file operations. 165 */ 166int drm_stub_open(struct inode *inode, struct file *filp) 167{ 168 struct drm_device *dev = NULL; 169 struct drm_minor *minor; 170 int minor_id = iminor(inode); 171 int err = -ENODEV; 172 const struct file_operations *old_fops; 173 174 DRM_DEBUG("\n"); 175 176 mutex_lock(&drm_global_mutex); 177 minor = idr_find(&drm_minors_idr, minor_id); 178 if (!minor) 179 goto out; 180 181 if (!(dev = minor->dev)) 182 goto out; 183 184 old_fops = filp->f_op; 185 filp->f_op = fops_get(&dev->driver->fops); 186 if (filp->f_op == NULL) { 187 filp->f_op = old_fops; 188 goto out; 189 } 190 if (filp->f_op->open && (err = filp->f_op->open(inode, filp))) { 191 fops_put(filp->f_op); 192 filp->f_op = fops_get(old_fops); 193 } 194 fops_put(old_fops); 195 196out: 197 mutex_unlock(&drm_global_mutex); 198 return err; 199} 200 201/** 202 * Check whether DRI will run on this CPU. 203 * 204 * \return non-zero if the DRI will run on this CPU, or zero otherwise. 205 */ 206static int drm_cpu_valid(void) 207{ 208#if defined(__i386__) 209 if (boot_cpu_data.x86 == 3) 210 return 0; /* No cmpxchg on a 386 */ 211#endif 212#if defined(__sparc__) && !defined(__sparc_v9__) 213 return 0; /* No cmpxchg before v9 sparc. */ 214#endif 215 return 1; 216} 217 218/** 219 * Called whenever a process opens /dev/drm. 220 * 221 * \param inode device inode. 222 * \param filp file pointer. 223 * \param dev device. 224 * \return zero on success or a negative number on failure. 225 * 226 * Creates and initializes a drm_file structure for the file private data in \p 227 * filp and add it into the double linked list in \p dev. 228 */ 229static int drm_open_helper(struct inode *inode, struct file *filp, 230 struct drm_device * dev) 231{ 232 int minor_id = iminor(inode); 233 struct drm_file *priv; 234 int ret; 235 236 if (filp->f_flags & O_EXCL) 237 return -EBUSY; /* No exclusive opens */ 238 if (!drm_cpu_valid()) 239 return -EINVAL; 240 241 DRM_DEBUG("pid = %d, minor = %d\n", task_pid_nr(current), minor_id); 242 243 priv = kzalloc(sizeof(*priv), GFP_KERNEL); 244 if (!priv) 245 return -ENOMEM; 246 247 filp->private_data = priv; 248 priv->filp = filp; 249 priv->uid = current_euid(); 250 priv->pid = task_pid_nr(current); 251 priv->minor = idr_find(&drm_minors_idr, minor_id); 252 priv->ioctl_count = 0; 253 /* for compatibility root is always authenticated */ 254 priv->authenticated = capable(CAP_SYS_ADMIN); 255 priv->lock_count = 0; 256 257 INIT_LIST_HEAD(&priv->lhead); 258 INIT_LIST_HEAD(&priv->fbs); 259 INIT_LIST_HEAD(&priv->event_list); 260 init_waitqueue_head(&priv->event_wait); 261 priv->event_space = 4096; /* set aside 4k for event buffer */ 262 263 if (dev->driver->driver_features & DRIVER_GEM) 264 drm_gem_open(dev, priv); 265 266 if (dev->driver->open) { 267 ret = dev->driver->open(dev, priv); 268 if (ret < 0) 269 goto out_free; 270 } 271 272 273 /* if there is no current master make this fd it */ 274 mutex_lock(&dev->struct_mutex); 275 if (!priv->minor->master) { 276 /* create a new master */ 277 priv->minor->master = drm_master_create(priv->minor); 278 if (!priv->minor->master) { 279 mutex_unlock(&dev->struct_mutex); 280 ret = -ENOMEM; 281 goto out_free; 282 } 283 284 priv->is_master = 1; 285 /* take another reference for the copy in the local file priv */ 286 priv->master = drm_master_get(priv->minor->master); 287 288 priv->authenticated = 1; 289 290 mutex_unlock(&dev->struct_mutex); 291 if (dev->driver->master_create) { 292 ret = dev->driver->master_create(dev, priv->master); 293 if (ret) { 294 mutex_lock(&dev->struct_mutex); 295 /* drop both references if this fails */ 296 drm_master_put(&priv->minor->master); 297 drm_master_put(&priv->master); 298 mutex_unlock(&dev->struct_mutex); 299 goto out_free; 300 } 301 } 302 mutex_lock(&dev->struct_mutex); 303 if (dev->driver->master_set) { 304 ret = dev->driver->master_set(dev, priv, true); 305 if (ret) { 306 /* drop both references if this fails */ 307 drm_master_put(&priv->minor->master); 308 drm_master_put(&priv->master); 309 mutex_unlock(&dev->struct_mutex); 310 goto out_free; 311 } 312 } 313 mutex_unlock(&dev->struct_mutex); 314 } else { 315 /* get a reference to the master */ 316 priv->master = drm_master_get(priv->minor->master); 317 mutex_unlock(&dev->struct_mutex); 318 } 319 320 mutex_lock(&dev->struct_mutex); 321 list_add(&priv->lhead, &dev->filelist); 322 mutex_unlock(&dev->struct_mutex); 323 324#ifdef __alpha__ 325 /* 326 * Default the hose 327 */ 328 if (!dev->hose) { 329 struct pci_dev *pci_dev; 330 pci_dev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, NULL); 331 if (pci_dev) { 332 dev->hose = pci_dev->sysdata; 333 pci_dev_put(pci_dev); 334 } 335 if (!dev->hose) { 336 struct pci_bus *b = pci_bus_b(pci_root_buses.next); 337 if (b) 338 dev->hose = b->sysdata; 339 } 340 } 341#endif 342 343 return 0; 344 out_free: 345 kfree(priv); 346 filp->private_data = NULL; 347 return ret; 348} 349 350/** No-op. */ 351int drm_fasync(int fd, struct file *filp, int on) 352{ 353 struct drm_file *priv = filp->private_data; 354 struct drm_device *dev = priv->minor->dev; 355 356 DRM_DEBUG("fd = %d, device = 0x%lx\n", fd, 357 (long)old_encode_dev(priv->minor->device)); 358 return fasync_helper(fd, filp, on, &dev->buf_async); 359} 360EXPORT_SYMBOL(drm_fasync); 361 362/* 363 * Reclaim locked buffers; note that this may be a bad idea if the current 364 * context doesn't have the hw lock... 365 */ 366static void drm_reclaim_locked_buffers(struct drm_device *dev, struct file *f) 367{ 368 struct drm_file *file_priv = f->private_data; 369 370 if (drm_i_have_hw_lock(dev, file_priv)) { 371 dev->driver->reclaim_buffers_locked(dev, file_priv); 372 } else { 373 unsigned long _end = jiffies + 3 * DRM_HZ; 374 int locked = 0; 375 376 drm_idlelock_take(&file_priv->master->lock); 377 378 /* 379 * Wait for a while. 380 */ 381 do { 382 spin_lock_bh(&file_priv->master->lock.spinlock); 383 locked = file_priv->master->lock.idle_has_lock; 384 spin_unlock_bh(&file_priv->master->lock.spinlock); 385 if (locked) 386 break; 387 schedule(); 388 } while (!time_after_eq(jiffies, _end)); 389 390 if (!locked) { 391 DRM_ERROR("reclaim_buffers_locked() deadlock. Please rework this\n" 392 "\tdriver to use reclaim_buffers_idlelocked() instead.\n" 393 "\tI will go on reclaiming the buffers anyway.\n"); 394 } 395 396 dev->driver->reclaim_buffers_locked(dev, file_priv); 397 drm_idlelock_release(&file_priv->master->lock); 398 } 399} 400 401static void drm_master_release(struct drm_device *dev, struct file *filp) 402{ 403 struct drm_file *file_priv = filp->private_data; 404 405 if (dev->driver->reclaim_buffers_locked && 406 file_priv->master->lock.hw_lock) 407 drm_reclaim_locked_buffers(dev, filp); 408 409 if (dev->driver->reclaim_buffers_idlelocked && 410 file_priv->master->lock.hw_lock) { 411 drm_idlelock_take(&file_priv->master->lock); 412 dev->driver->reclaim_buffers_idlelocked(dev, file_priv); 413 drm_idlelock_release(&file_priv->master->lock); 414 } 415 416 417 if (drm_i_have_hw_lock(dev, file_priv)) { 418 DRM_DEBUG("File %p released, freeing lock for context %d\n", 419 filp, _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock)); 420 drm_lock_free(&file_priv->master->lock, 421 _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock)); 422 } 423 424 if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) && 425 !dev->driver->reclaim_buffers_locked) { 426 dev->driver->reclaim_buffers(dev, file_priv); 427 } 428} 429 430static void drm_events_release(struct drm_file *file_priv) 431{ 432 struct drm_device *dev = file_priv->minor->dev; 433 struct drm_pending_event *e, *et; 434 struct drm_pending_vblank_event *v, *vt; 435 unsigned long flags; 436 437 spin_lock_irqsave(&dev->event_lock, flags); 438 439 /* Remove pending flips */ 440 list_for_each_entry_safe(v, vt, &dev->vblank_event_list, base.link) 441 if (v->base.file_priv == file_priv) { 442 list_del(&v->base.link); 443 drm_vblank_put(dev, v->pipe); 444 v->base.destroy(&v->base); 445 } 446 447 /* Remove unconsumed events */ 448 list_for_each_entry_safe(e, et, &file_priv->event_list, link) 449 e->destroy(e); 450 451 spin_unlock_irqrestore(&dev->event_lock, flags); 452} 453 454/** 455 * Release file. 456 * 457 * \param inode device inode 458 * \param file_priv DRM file private. 459 * \return zero on success or a negative number on failure. 460 * 461 * If the hardware lock is held then free it, and take it again for the kernel 462 * context since it's necessary to reclaim buffers. Unlink the file private 463 * data from its list and free it. Decreases the open count and if it reaches 464 * zero calls drm_lastclose(). 465 */ 466int drm_release(struct inode *inode, struct file *filp) 467{ 468 struct drm_file *file_priv = filp->private_data; 469 struct drm_device *dev = file_priv->minor->dev; 470 int retcode = 0; 471 472 mutex_lock(&drm_global_mutex); 473 474 DRM_DEBUG("open_count = %d\n", dev->open_count); 475 476 if (dev->driver->preclose) 477 dev->driver->preclose(dev, file_priv); 478 479 /* ======================================================== 480 * Begin inline drm_release 481 */ 482 483 DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n", 484 task_pid_nr(current), 485 (long)old_encode_dev(file_priv->minor->device), 486 dev->open_count); 487 488 /* if the master has gone away we can't do anything with the lock */ 489 if (file_priv->minor->master) 490 drm_master_release(dev, filp); 491 492 drm_events_release(file_priv); 493 494 if (dev->driver->driver_features & DRIVER_GEM) 495 drm_gem_release(dev, file_priv); 496 497 if (dev->driver->driver_features & DRIVER_MODESET) 498 drm_fb_release(file_priv); 499 500 mutex_lock(&dev->ctxlist_mutex); 501 if (!list_empty(&dev->ctxlist)) { 502 struct drm_ctx_list *pos, *n; 503 504 list_for_each_entry_safe(pos, n, &dev->ctxlist, head) { 505 if (pos->tag == file_priv && 506 pos->handle != DRM_KERNEL_CONTEXT) { 507 if (dev->driver->context_dtor) 508 dev->driver->context_dtor(dev, 509 pos->handle); 510 511 drm_ctxbitmap_free(dev, pos->handle); 512 513 list_del(&pos->head); 514 kfree(pos); 515 --dev->ctx_count; 516 } 517 } 518 } 519 mutex_unlock(&dev->ctxlist_mutex); 520 521 mutex_lock(&dev->struct_mutex); 522 523 if (file_priv->is_master) { 524 struct drm_master *master = file_priv->master; 525 struct drm_file *temp; 526 list_for_each_entry(temp, &dev->filelist, lhead) { 527 if ((temp->master == file_priv->master) && 528 (temp != file_priv)) 529 temp->authenticated = 0; 530 } 531 532 /** 533 * Since the master is disappearing, so is the 534 * possibility to lock. 535 */ 536 537 if (master->lock.hw_lock) { 538 if (dev->sigdata.lock == master->lock.hw_lock) 539 dev->sigdata.lock = NULL; 540 master->lock.hw_lock = NULL; 541 master->lock.file_priv = NULL; 542 wake_up_interruptible_all(&master->lock.lock_queue); 543 } 544 545 if (file_priv->minor->master == file_priv->master) { 546 /* drop the reference held my the minor */ 547 if (dev->driver->master_drop) 548 dev->driver->master_drop(dev, file_priv, true); 549 drm_master_put(&file_priv->minor->master); 550 } 551 } 552 553 /* drop the reference held my the file priv */ 554 drm_master_put(&file_priv->master); 555 file_priv->is_master = 0; 556 list_del(&file_priv->lhead); 557 mutex_unlock(&dev->struct_mutex); 558 559 if (dev->driver->postclose) 560 dev->driver->postclose(dev, file_priv); 561 kfree(file_priv); 562 563 /* ======================================================== 564 * End inline drm_release 565 */ 566 567 atomic_inc(&dev->counts[_DRM_STAT_CLOSES]); 568 if (!--dev->open_count) { 569 if (atomic_read(&dev->ioctl_count)) { 570 DRM_ERROR("Device busy: %d\n", 571 atomic_read(&dev->ioctl_count)); 572 retcode = -EBUSY; 573 } else 574 retcode = drm_lastclose(dev); 575 } 576 mutex_unlock(&drm_global_mutex); 577 578 return retcode; 579} 580EXPORT_SYMBOL(drm_release); 581 582static bool 583drm_dequeue_event(struct drm_file *file_priv, 584 size_t total, size_t max, struct drm_pending_event **out) 585{ 586 struct drm_device *dev = file_priv->minor->dev; 587 struct drm_pending_event *e; 588 unsigned long flags; 589 bool ret = false; 590 591 spin_lock_irqsave(&dev->event_lock, flags); 592 593 *out = NULL; 594 if (list_empty(&file_priv->event_list)) 595 goto out; 596 e = list_first_entry(&file_priv->event_list, 597 struct drm_pending_event, link); 598 if (e->event->length + total > max) 599 goto out; 600 601 file_priv->event_space += e->event->length; 602 list_del(&e->link); 603 *out = e; 604 ret = true; 605 606out: 607 spin_unlock_irqrestore(&dev->event_lock, flags); 608 return ret; 609} 610 611ssize_t drm_read(struct file *filp, char __user *buffer, 612 size_t count, loff_t *offset) 613{ 614 struct drm_file *file_priv = filp->private_data; 615 struct drm_pending_event *e; 616 size_t total; 617 ssize_t ret; 618 619 ret = wait_event_interruptible(file_priv->event_wait, 620 !list_empty(&file_priv->event_list)); 621 if (ret < 0) 622 return ret; 623 624 total = 0; 625 while (drm_dequeue_event(file_priv, total, count, &e)) { 626 if (copy_to_user(buffer + total, 627 e->event, e->event->length)) { 628 total = -EFAULT; 629 break; 630 } 631 632 total += e->event->length; 633 e->destroy(e); 634 } 635 636 return total; 637} 638EXPORT_SYMBOL(drm_read); 639 640unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait) 641{ 642 struct drm_file *file_priv = filp->private_data; 643 unsigned int mask = 0; 644 645 poll_wait(filp, &file_priv->event_wait, wait); 646 647 if (!list_empty(&file_priv->event_list)) 648 mask |= POLLIN | POLLRDNORM; 649 650 return mask; 651} 652EXPORT_SYMBOL(drm_poll); 653