linux/drivers/gpu/drm/drm_fops.c
<<
>>
Prefs
   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/smp_lock.h>
  40
  41static int drm_open_helper(struct inode *inode, struct file *filp,
  42                           struct drm_device * dev);
  43
  44static int drm_setup(struct drm_device * dev)
  45{
  46        int i;
  47        int ret;
  48
  49        if (dev->driver->firstopen) {
  50                ret = dev->driver->firstopen(dev);
  51                if (ret != 0)
  52                        return ret;
  53        }
  54
  55        atomic_set(&dev->ioctl_count, 0);
  56        atomic_set(&dev->vma_count, 0);
  57
  58        if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) &&
  59            !drm_core_check_feature(dev, DRIVER_MODESET)) {
  60                dev->buf_use = 0;
  61                atomic_set(&dev->buf_alloc, 0);
  62
  63                i = drm_dma_setup(dev);
  64                if (i < 0)
  65                        return i;
  66        }
  67
  68        for (i = 0; i < ARRAY_SIZE(dev->counts); i++)
  69                atomic_set(&dev->counts[i], 0);
  70
  71        dev->sigdata.lock = NULL;
  72
  73        dev->queue_count = 0;
  74        dev->queue_reserved = 0;
  75        dev->queue_slots = 0;
  76        dev->queuelist = NULL;
  77        dev->context_flag = 0;
  78        dev->interrupt_flag = 0;
  79        dev->dma_flag = 0;
  80        dev->last_context = 0;
  81        dev->last_switch = 0;
  82        dev->last_checked = 0;
  83        init_waitqueue_head(&dev->context_wait);
  84        dev->if_version = 0;
  85
  86        dev->ctx_start = 0;
  87        dev->lck_start = 0;
  88
  89        dev->buf_async = NULL;
  90        init_waitqueue_head(&dev->buf_readers);
  91        init_waitqueue_head(&dev->buf_writers);
  92
  93        DRM_DEBUG("\n");
  94
  95        /*
  96         * The kernel's context could be created here, but is now created
  97         * in drm_dma_enqueue.  This is more resource-efficient for
  98         * hardware that does not do DMA, but may mean that
  99         * drm_select_queue fails between the time the interrupt is
 100         * initialized and the time the queues are initialized.
 101         */
 102
 103        return 0;
 104}
 105
 106/**
 107 * Open file.
 108 *
 109 * \param inode device inode
 110 * \param filp file pointer.
 111 * \return zero on success or a negative number on failure.
 112 *
 113 * Searches the DRM device with the same minor number, calls open_helper(), and
 114 * increments the device open count. If the open count was previous at zero,
 115 * i.e., it's the first that the device is open, then calls setup().
 116 */
 117int drm_open(struct inode *inode, struct file *filp)
 118{
 119        struct drm_device *dev = NULL;
 120        int minor_id = iminor(inode);
 121        struct drm_minor *minor;
 122        int retcode = 0;
 123
 124        minor = idr_find(&drm_minors_idr, minor_id);
 125        if (!minor)
 126                return -ENODEV;
 127
 128        if (!(dev = minor->dev))
 129                return -ENODEV;
 130
 131        retcode = drm_open_helper(inode, filp, dev);
 132        if (!retcode) {
 133                atomic_inc(&dev->counts[_DRM_STAT_OPENS]);
 134                spin_lock(&dev->count_lock);
 135                if (!dev->open_count++) {
 136                        spin_unlock(&dev->count_lock);
 137                        retcode = drm_setup(dev);
 138                        goto out;
 139                }
 140                spin_unlock(&dev->count_lock);
 141        }
 142out:
 143        mutex_lock(&dev->struct_mutex);
 144        if (minor->type == DRM_MINOR_LEGACY) {
 145                BUG_ON((dev->dev_mapping != NULL) &&
 146                        (dev->dev_mapping != inode->i_mapping));
 147                if (dev->dev_mapping == NULL)
 148                        dev->dev_mapping = inode->i_mapping;
 149        }
 150        mutex_unlock(&dev->struct_mutex);
 151
 152        return retcode;
 153}
 154EXPORT_SYMBOL(drm_open);
 155
 156/**
 157 * File \c open operation.
 158 *
 159 * \param inode device inode.
 160 * \param filp file pointer.
 161 *
 162 * Puts the dev->fops corresponding to the device minor number into
 163 * \p filp, call the \c open method, and restore the file operations.
 164 */
 165int drm_stub_open(struct inode *inode, struct file *filp)
 166{
 167        struct drm_device *dev = NULL;
 168        struct drm_minor *minor;
 169        int minor_id = iminor(inode);
 170        int err = -ENODEV;
 171        const struct file_operations *old_fops;
 172
 173        DRM_DEBUG("\n");
 174
 175        /* BKL pushdown: note that nothing else serializes idr_find() */
 176        lock_kernel();
 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        unlock_kernel();
 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 = kmalloc(sizeof(*priv), GFP_KERNEL);
 244        if (!priv)
 245                return -ENOMEM;
 246
 247        memset(priv, 0, sizeof(*priv));
 248        filp->private_data = priv;
 249        priv->filp = filp;
 250        priv->uid = current_euid();
 251        priv->pid = task_pid_nr(current);
 252        priv->minor = idr_find(&drm_minors_idr, minor_id);
 253        priv->ioctl_count = 0;
 254        /* for compatibility root is always authenticated */
 255        priv->authenticated = capable(CAP_SYS_ADMIN);
 256        priv->lock_count = 0;
 257
 258        INIT_LIST_HEAD(&priv->lhead);
 259        INIT_LIST_HEAD(&priv->fbs);
 260
 261        if (dev->driver->driver_features & DRIVER_GEM)
 262                drm_gem_open(dev, priv);
 263
 264        if (dev->driver->open) {
 265                ret = dev->driver->open(dev, priv);
 266                if (ret < 0)
 267                        goto out_free;
 268        }
 269
 270
 271        /* if there is no current master make this fd it */
 272        mutex_lock(&dev->struct_mutex);
 273        if (!priv->minor->master) {
 274                /* create a new master */
 275                priv->minor->master = drm_master_create(priv->minor);
 276                if (!priv->minor->master) {
 277                        mutex_unlock(&dev->struct_mutex);
 278                        ret = -ENOMEM;
 279                        goto out_free;
 280                }
 281
 282                priv->is_master = 1;
 283                /* take another reference for the copy in the local file priv */
 284                priv->master = drm_master_get(priv->minor->master);
 285
 286                priv->authenticated = 1;
 287
 288                mutex_unlock(&dev->struct_mutex);
 289                if (dev->driver->master_create) {
 290                        ret = dev->driver->master_create(dev, priv->master);
 291                        if (ret) {
 292                                mutex_lock(&dev->struct_mutex);
 293                                /* drop both references if this fails */
 294                                drm_master_put(&priv->minor->master);
 295                                drm_master_put(&priv->master);
 296                                mutex_unlock(&dev->struct_mutex);
 297                                goto out_free;
 298                        }
 299                }
 300        } else {
 301                /* get a reference to the master */
 302                priv->master = drm_master_get(priv->minor->master);
 303                mutex_unlock(&dev->struct_mutex);
 304        }
 305
 306        mutex_lock(&dev->struct_mutex);
 307        list_add(&priv->lhead, &dev->filelist);
 308        mutex_unlock(&dev->struct_mutex);
 309
 310#ifdef __alpha__
 311        /*
 312         * Default the hose
 313         */
 314        if (!dev->hose) {
 315                struct pci_dev *pci_dev;
 316                pci_dev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, NULL);
 317                if (pci_dev) {
 318                        dev->hose = pci_dev->sysdata;
 319                        pci_dev_put(pci_dev);
 320                }
 321                if (!dev->hose) {
 322                        struct pci_bus *b = pci_bus_b(pci_root_buses.next);
 323                        if (b)
 324                                dev->hose = b->sysdata;
 325                }
 326        }
 327#endif
 328
 329        return 0;
 330      out_free:
 331        kfree(priv);
 332        filp->private_data = NULL;
 333        return ret;
 334}
 335
 336/** No-op. */
 337int drm_fasync(int fd, struct file *filp, int on)
 338{
 339        struct drm_file *priv = filp->private_data;
 340        struct drm_device *dev = priv->minor->dev;
 341
 342        DRM_DEBUG("fd = %d, device = 0x%lx\n", fd,
 343                  (long)old_encode_dev(priv->minor->device));
 344        return fasync_helper(fd, filp, on, &dev->buf_async);
 345}
 346EXPORT_SYMBOL(drm_fasync);
 347
 348/*
 349 * Reclaim locked buffers; note that this may be a bad idea if the current
 350 * context doesn't have the hw lock...
 351 */
 352static void drm_reclaim_locked_buffers(struct drm_device *dev, struct file *f)
 353{
 354        struct drm_file *file_priv = f->private_data;
 355
 356        if (drm_i_have_hw_lock(dev, file_priv)) {
 357                dev->driver->reclaim_buffers_locked(dev, file_priv);
 358        } else {
 359                unsigned long _end = jiffies + 3 * DRM_HZ;
 360                int locked = 0;
 361
 362                drm_idlelock_take(&file_priv->master->lock);
 363
 364                /*
 365                 * Wait for a while.
 366                 */
 367                do {
 368                        spin_lock_bh(&file_priv->master->lock.spinlock);
 369                        locked = file_priv->master->lock.idle_has_lock;
 370                        spin_unlock_bh(&file_priv->master->lock.spinlock);
 371                        if (locked)
 372                                break;
 373                        schedule();
 374                } while (!time_after_eq(jiffies, _end));
 375
 376                if (!locked) {
 377                        DRM_ERROR("reclaim_buffers_locked() deadlock. Please rework this\n"
 378                                  "\tdriver to use reclaim_buffers_idlelocked() instead.\n"
 379                                  "\tI will go on reclaiming the buffers anyway.\n");
 380                }
 381
 382                dev->driver->reclaim_buffers_locked(dev, file_priv);
 383                drm_idlelock_release(&file_priv->master->lock);
 384        }
 385}
 386
 387static void drm_master_release(struct drm_device *dev, struct file *filp)
 388{
 389        struct drm_file *file_priv = filp->private_data;
 390
 391        if (dev->driver->reclaim_buffers_locked &&
 392            file_priv->master->lock.hw_lock)
 393                drm_reclaim_locked_buffers(dev, filp);
 394
 395        if (dev->driver->reclaim_buffers_idlelocked &&
 396            file_priv->master->lock.hw_lock) {
 397                drm_idlelock_take(&file_priv->master->lock);
 398                dev->driver->reclaim_buffers_idlelocked(dev, file_priv);
 399                drm_idlelock_release(&file_priv->master->lock);
 400        }
 401
 402
 403        if (drm_i_have_hw_lock(dev, file_priv)) {
 404                DRM_DEBUG("File %p released, freeing lock for context %d\n",
 405                          filp, _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock));
 406                drm_lock_free(&file_priv->master->lock,
 407                              _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock));
 408        }
 409
 410        if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) &&
 411            !dev->driver->reclaim_buffers_locked) {
 412                dev->driver->reclaim_buffers(dev, file_priv);
 413        }
 414}
 415
 416/**
 417 * Release file.
 418 *
 419 * \param inode device inode
 420 * \param file_priv DRM file private.
 421 * \return zero on success or a negative number on failure.
 422 *
 423 * If the hardware lock is held then free it, and take it again for the kernel
 424 * context since it's necessary to reclaim buffers. Unlink the file private
 425 * data from its list and free it. Decreases the open count and if it reaches
 426 * zero calls drm_lastclose().
 427 */
 428int drm_release(struct inode *inode, struct file *filp)
 429{
 430        struct drm_file *file_priv = filp->private_data;
 431        struct drm_device *dev = file_priv->minor->dev;
 432        int retcode = 0;
 433
 434        lock_kernel();
 435
 436        DRM_DEBUG("open_count = %d\n", dev->open_count);
 437
 438        if (dev->driver->preclose)
 439                dev->driver->preclose(dev, file_priv);
 440
 441        /* ========================================================
 442         * Begin inline drm_release
 443         */
 444
 445        DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n",
 446                  task_pid_nr(current),
 447                  (long)old_encode_dev(file_priv->minor->device),
 448                  dev->open_count);
 449
 450        /* if the master has gone away we can't do anything with the lock */
 451        if (file_priv->minor->master)
 452                drm_master_release(dev, filp);
 453
 454        if (dev->driver->driver_features & DRIVER_GEM)
 455                drm_gem_release(dev, file_priv);
 456
 457        if (dev->driver->driver_features & DRIVER_MODESET)
 458                drm_fb_release(file_priv);
 459
 460        mutex_lock(&dev->ctxlist_mutex);
 461        if (!list_empty(&dev->ctxlist)) {
 462                struct drm_ctx_list *pos, *n;
 463
 464                list_for_each_entry_safe(pos, n, &dev->ctxlist, head) {
 465                        if (pos->tag == file_priv &&
 466                            pos->handle != DRM_KERNEL_CONTEXT) {
 467                                if (dev->driver->context_dtor)
 468                                        dev->driver->context_dtor(dev,
 469                                                                  pos->handle);
 470
 471                                drm_ctxbitmap_free(dev, pos->handle);
 472
 473                                list_del(&pos->head);
 474                                kfree(pos);
 475                                --dev->ctx_count;
 476                        }
 477                }
 478        }
 479        mutex_unlock(&dev->ctxlist_mutex);
 480
 481        mutex_lock(&dev->struct_mutex);
 482
 483        if (file_priv->is_master) {
 484                struct drm_master *master = file_priv->master;
 485                struct drm_file *temp;
 486                list_for_each_entry(temp, &dev->filelist, lhead) {
 487                        if ((temp->master == file_priv->master) &&
 488                            (temp != file_priv))
 489                                temp->authenticated = 0;
 490                }
 491
 492                /**
 493                 * Since the master is disappearing, so is the
 494                 * possibility to lock.
 495                 */
 496
 497                if (master->lock.hw_lock) {
 498                        if (dev->sigdata.lock == master->lock.hw_lock)
 499                                dev->sigdata.lock = NULL;
 500                        master->lock.hw_lock = NULL;
 501                        master->lock.file_priv = NULL;
 502                        wake_up_interruptible_all(&master->lock.lock_queue);
 503                }
 504
 505                if (file_priv->minor->master == file_priv->master) {
 506                        /* drop the reference held my the minor */
 507                        drm_master_put(&file_priv->minor->master);
 508                }
 509        }
 510
 511        /* drop the reference held my the file priv */
 512        drm_master_put(&file_priv->master);
 513        file_priv->is_master = 0;
 514        list_del(&file_priv->lhead);
 515        mutex_unlock(&dev->struct_mutex);
 516
 517        if (dev->driver->postclose)
 518                dev->driver->postclose(dev, file_priv);
 519        kfree(file_priv);
 520
 521        /* ========================================================
 522         * End inline drm_release
 523         */
 524
 525        atomic_inc(&dev->counts[_DRM_STAT_CLOSES]);
 526        spin_lock(&dev->count_lock);
 527        if (!--dev->open_count) {
 528                if (atomic_read(&dev->ioctl_count)) {
 529                        DRM_ERROR("Device busy: %d\n",
 530                                  atomic_read(&dev->ioctl_count));
 531                        spin_unlock(&dev->count_lock);
 532                        unlock_kernel();
 533                        return -EBUSY;
 534                }
 535                spin_unlock(&dev->count_lock);
 536                unlock_kernel();
 537                return drm_lastclose(dev);
 538        }
 539        spin_unlock(&dev->count_lock);
 540
 541        unlock_kernel();
 542
 543        return retcode;
 544}
 545EXPORT_SYMBOL(drm_release);
 546
 547/** No-op. */
 548unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait)
 549{
 550        return 0;
 551}
 552EXPORT_SYMBOL(drm_poll);
 553