OSDN Git Service

Merge remote branch 'origin/master' into modesetting-gem
[android-x86/external-libdrm.git] / linux-core / drm_fops.c
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 "drm_sarea.h"
39 #include <linux/poll.h>
40
41 static int drm_open_helper(struct inode *inode, struct file *filp,
42                            struct drm_device * dev);
43
44 static 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) && !drm_core_check_feature(dev, DRIVER_MODESET)) {
59                 dev->buf_use = 0;
60                 atomic_set(&dev->buf_alloc, 0);
61
62                 i = drm_dma_setup(dev);
63                 if (i < 0)
64                         return i;
65         }
66
67         for (i = 0; i < ARRAY_SIZE(dev->counts); i++)
68                 atomic_set(&dev->counts[i], 0);
69
70         dev->sigdata.lock = NULL;
71
72         dev->queue_count = 0;
73         dev->queue_reserved = 0;
74         dev->queue_slots = 0;
75         dev->queuelist = NULL;
76         dev->context_flag = 0;
77         dev->interrupt_flag = 0;
78         dev->dma_flag = 0;
79         dev->last_context = 0;
80         dev->last_switch = 0;
81         dev->last_checked = 0;
82         init_waitqueue_head(&dev->context_wait);
83         dev->if_version = 0;
84
85         dev->ctx_start = 0;
86         dev->lck_start = 0;
87
88         dev->buf_async = NULL;
89         init_waitqueue_head(&dev->buf_readers);
90         init_waitqueue_head(&dev->buf_writers);
91
92         DRM_DEBUG("\n");
93
94         /*
95          * The kernel's context could be created here, but is now created
96          * in drm_dma_enqueue.  This is more resource-efficient for
97          * hardware that does not do DMA, but may mean that
98          * drm_select_queue fails between the time the interrupt is
99          * initialized and the time the queues are initialized.
100          */
101
102         return 0;
103 }
104
105 /**
106  * Open file.
107  *
108  * \param inode device inode
109  * \param filp file pointer.
110  * \return zero on success or a negative number on failure.
111  *
112  * Searches the DRM device with the same minor number, calls open_helper(), and
113  * increments the device open count. If the open count was previous at zero,
114  * i.e., it's the first that the device is open, then calls setup().
115  */
116 int drm_open(struct inode *inode, struct file *filp)
117 {
118         struct drm_device *dev = NULL;
119         int minor_id = iminor(inode);
120         struct drm_minor *minor;
121         int retcode = 0;
122
123         minor = idr_find(&drm_minors_idr, minor_id);
124         if (!minor)
125                 return -ENODEV;
126
127         if (!(dev = minor->dev))
128                 return -ENODEV;
129
130         retcode = drm_open_helper(inode, filp, dev);
131         if (!retcode) {
132                 atomic_inc(&dev->counts[_DRM_STAT_OPENS]);
133                 spin_lock(&dev->count_lock);
134                 if (!dev->open_count++) {
135                         spin_unlock(&dev->count_lock);
136                         retcode = drm_setup(dev);
137                         goto out;
138                 }
139                 spin_unlock(&dev->count_lock);
140         }
141
142 out:
143         mutex_lock(&dev->struct_mutex);
144         BUG_ON((dev->dev_mapping != NULL) &&
145                (dev->dev_mapping != inode->i_mapping));
146         if (dev->dev_mapping == NULL)
147                 dev->dev_mapping = inode->i_mapping;
148         mutex_unlock(&dev->struct_mutex);
149
150         return retcode;
151 }
152 EXPORT_SYMBOL(drm_open);
153
154 /**
155  * File \c open operation.
156  *
157  * \param inode device inode.
158  * \param filp file pointer.
159  *
160  * Puts the dev->fops corresponding to the device minor number into
161  * \p filp, call the \c open method, and restore the file operations.
162  */
163 int drm_stub_open(struct inode *inode, struct file *filp)
164 {
165         struct drm_device *dev = NULL;
166         struct drm_minor *minor;
167         int minor_id = iminor(inode);
168         int err = -ENODEV;
169         const struct file_operations *old_fops;
170
171         DRM_DEBUG("\n");
172
173         minor = idr_find(&drm_minors_idr, minor_id);
174         if (!minor)
175                 return -ENODEV;
176         
177         if (!(dev = minor->dev))
178                 return -ENODEV;
179
180         old_fops = filp->f_op;
181         filp->f_op = fops_get(&dev->driver->fops);
182         if (filp->f_op->open && (err = filp->f_op->open(inode, filp))) {
183                 fops_put(filp->f_op);
184                 filp->f_op = fops_get(old_fops);
185         }
186         fops_put(old_fops);
187
188         return err;
189 }
190
191 /**
192  * Check whether DRI will run on this CPU.
193  *
194  * \return non-zero if the DRI will run on this CPU, or zero otherwise.
195  */
196 static int drm_cpu_valid(void)
197 {
198 #if defined(__i386__)
199         if (boot_cpu_data.x86 == 3)
200                 return 0;       /* No cmpxchg on a 386 */
201 #endif
202 #if defined(__sparc__) && !defined(__sparc_v9__)
203         return 0;               /* No cmpxchg before v9 sparc. */
204 #endif
205         return 1;
206 }
207
208 /**
209  * Called whenever a process opens /dev/drm.
210  *
211  * \param inode device inode.
212  * \param filp file pointer.
213  * \param dev device.
214  * \return zero on success or a negative number on failure.
215  *
216  * Creates and initializes a drm_file structure for the file private data in \p
217  * filp and add it into the double linked list in \p dev.
218  */
219 static int drm_open_helper(struct inode *inode, struct file *filp,
220                            struct drm_device * dev)
221 {
222         int minor_id = iminor(inode);
223         struct drm_file *priv;
224         int ret;
225
226         if (filp->f_flags & O_EXCL)
227                 return -EBUSY;  /* No exclusive opens */
228         if (!drm_cpu_valid())
229                 return -EINVAL;
230
231         DRM_DEBUG("pid = %d, minor = %d\n", current->pid, minor_id);
232
233         priv = drm_alloc(sizeof(*priv), DRM_MEM_FILES);
234         if (!priv)
235                 return -ENOMEM;
236
237         memset(priv, 0, sizeof(*priv));
238         filp->private_data = priv;
239         priv->filp = filp;
240         priv->uid = current->euid;
241         priv->pid = current->pid;
242         priv->minor = idr_find(&drm_minors_idr, minor_id);
243         priv->ioctl_count = 0;
244         /* for compatibility root is always authenticated */
245         priv->authenticated = capable(CAP_SYS_ADMIN);
246         priv->lock_count = 0;
247
248         INIT_LIST_HEAD(&priv->lhead);
249         INIT_LIST_HEAD(&priv->fbs);
250
251         if (dev->driver->driver_features & DRIVER_GEM)
252                 drm_gem_open(dev, priv);
253
254         if (dev->driver->open) {
255                 ret = dev->driver->open(dev, priv);
256                 if (ret < 0)
257                         goto out_free;
258         }
259
260
261         /* if there is no current master make this fd it */
262         mutex_lock(&dev->struct_mutex);
263         if (!priv->minor->master) {
264                 /* create a new master */
265                 priv->minor->master = drm_master_create(priv->minor);
266                 if (!priv->minor->master) {
267                         ret = -ENOMEM;
268                         goto out_free;
269                 }
270
271                 priv->is_master = 1;
272                 /* take another reference for the copy in the local file priv */
273                 priv->master = drm_master_get(priv->minor->master);
274
275                 priv->authenticated = 1;
276
277                 mutex_unlock(&dev->struct_mutex);
278                 if (dev->driver->master_create) {
279                         ret = dev->driver->master_create(dev, priv->master);
280                         if (ret) {
281                                 mutex_lock(&dev->struct_mutex);
282                                 /* drop both references if this fails */
283                                 drm_master_put(&priv->minor->master);
284                                 drm_master_put(&priv->master);
285                                 mutex_unlock(&dev->struct_mutex);
286                                 goto out_free;
287                         }
288                 }
289         } else {
290                 /* get a reference to the master */
291                 priv->master = drm_master_get(priv->minor->master);
292                 mutex_unlock(&dev->struct_mutex);
293         }
294
295         mutex_lock(&dev->struct_mutex);
296         list_add(&priv->lhead, &dev->filelist);
297         mutex_unlock(&dev->struct_mutex);
298
299 #ifdef __alpha__
300         /*
301          * Default the hose
302          */
303         if (!dev->hose) {
304                 struct pci_dev *pci_dev;
305                 pci_dev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, NULL);
306                 if (pci_dev) {
307                         dev->hose = pci_dev->sysdata;
308                         pci_dev_put(pci_dev);
309                 }
310                 if (!dev->hose) {
311                         struct pci_bus *b = pci_bus_b(pci_root_buses.next);
312                         if (b)
313                                 dev->hose = b->sysdata;
314                 }
315         }
316 #endif
317
318         return 0;
319       out_free:
320         drm_free(priv, sizeof(*priv), DRM_MEM_FILES);
321         filp->private_data = NULL;
322         return ret;
323 }
324
325 /** No-op. */
326 int drm_fasync(int fd, struct file *filp, int on)
327 {
328         struct drm_file *priv = filp->private_data;
329         struct drm_device *dev = priv->minor->dev;
330         int retcode;
331
332         DRM_DEBUG("fd = %d, device = 0x%lx\n", fd,
333                   (long)old_encode_dev(priv->minor->device));
334         retcode = fasync_helper(fd, filp, on, &dev->buf_async);
335         if (retcode < 0)
336                 return retcode;
337         return 0;
338 }
339 EXPORT_SYMBOL(drm_fasync);
340
341 /**
342  * Release file.
343  *
344  * \param inode device inode
345  * \param file_priv DRM file private.
346  * \return zero on success or a negative number on failure.
347  *
348  * If the hardware lock is held then free it, and take it again for the kernel
349  * context since it's necessary to reclaim buffers. Unlink the file private
350  * data from its list and free it. Decreases the open count and if it reaches
351  * zero calls drm_lastclose().
352  */
353 int drm_release(struct inode *inode, struct file *filp)
354 {
355         struct drm_file *file_priv = filp->private_data;
356         struct drm_device *dev = file_priv->minor->dev;
357         int retcode = 0;
358
359         lock_kernel();
360
361         DRM_DEBUG("open_count = %d\n", dev->open_count);
362
363         if (dev->driver->preclose)
364                 dev->driver->preclose(dev, file_priv);
365
366         /* ========================================================
367          * Begin inline drm_release
368          */
369
370         DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n",
371                   current->pid, (long)old_encode_dev(file_priv->minor->device),
372                   dev->open_count);
373
374         /* if the master has gone away we can't do anything with the lock */
375         if (file_priv->minor->master) {
376                 if (dev->driver->reclaim_buffers_locked && file_priv->master->lock.hw_lock) {
377                         if (drm_i_have_hw_lock(dev, file_priv)) {
378                                 dev->driver->reclaim_buffers_locked(dev, file_priv);
379                         } else {
380                                 unsigned long _end=jiffies + 3*DRM_HZ;
381                                 int locked = 0;
382                                 
383                                 drm_idlelock_take(&file_priv->master->lock);
384                                 
385                                 /*
386                                  * Wait for a while.
387                                  */
388                                 
389                                 do{
390                                         spin_lock_bh(&file_priv->master->lock.spinlock);
391                                         locked = file_priv->master->lock.idle_has_lock;
392                                         spin_unlock_bh(&file_priv->master->lock.spinlock);
393                                         if (locked)
394                                                 break;
395                                         schedule();
396                                 } while (!time_after_eq(jiffies, _end));
397                                 
398                                 if (!locked) {
399                                         DRM_ERROR("reclaim_buffers_locked() deadlock. Please rework this\n"
400                                                   "\tdriver to use reclaim_buffers_idlelocked() instead.\n"
401                                                   "\tI will go on reclaiming the buffers anyway.\n");
402                                 }
403                                 
404                                 dev->driver->reclaim_buffers_locked(dev, file_priv);
405                                 drm_idlelock_release(&file_priv->master->lock);
406                         }
407                 }
408
409                 if (dev->driver->reclaim_buffers_idlelocked && file_priv->master->lock.hw_lock) {
410                         
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
418                 if (drm_i_have_hw_lock(dev, file_priv)) {
419                         DRM_DEBUG("File %p released, freeing lock for context %d\n",
420                                   filp, _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock));
421                         
422                         drm_lock_free(&file_priv->master->lock,
423                                       _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock));
424                 }
425                 
426
427                 if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) &&
428                     !dev->driver->reclaim_buffers_locked) {
429                         dev->driver->reclaim_buffers(dev, file_priv);
430                 }
431         }
432
433         if (dev->driver->driver_features & DRIVER_GEM)
434                 drm_gem_release(dev, file_priv);
435
436         drm_fasync(-1, filp, 0);
437
438         mutex_lock(&dev->ctxlist_mutex);
439
440         if (!list_empty(&dev->ctxlist)) {
441                 struct drm_ctx_list *pos, *n;
442
443                 list_for_each_entry_safe(pos, n, &dev->ctxlist, head) {
444                         if (pos->tag == file_priv &&
445                             pos->handle != DRM_KERNEL_CONTEXT) {
446                                 if (dev->driver->context_dtor)
447                                         dev->driver->context_dtor(dev,
448                                                                   pos->handle);
449
450                                 drm_ctxbitmap_free(dev, pos->handle);
451
452                                 list_del(&pos->head);
453                                 drm_free(pos, sizeof(*pos), DRM_MEM_CTXLIST);
454                                 --dev->ctx_count;
455                         }
456                 }
457         }
458         mutex_unlock(&dev->ctxlist_mutex);
459
460         if (drm_core_check_feature(dev, DRIVER_MODESET))
461                 drm_fb_release(filp);
462
463         mutex_lock(&dev->struct_mutex);
464
465         if (file_priv->is_master) {
466                 struct drm_file *temp;
467                 list_for_each_entry(temp, &dev->filelist, lhead) {
468                         if ((temp->master == file_priv->master) &&
469                             (temp != file_priv))
470                                 temp->authenticated = 0;
471                 }
472
473                 if (file_priv->minor->master == file_priv->master) {
474                         /* drop the reference held my the minor */
475                         drm_master_put(&file_priv->minor->master);
476                 }
477         }
478
479         /* drop the reference held my the file priv */
480         drm_master_put(&file_priv->master);
481         file_priv->is_master = 0;
482
483         list_del(&file_priv->lhead);
484         mutex_unlock(&dev->struct_mutex);
485
486         if (dev->driver->postclose)
487                 dev->driver->postclose(dev, file_priv);
488         drm_free(file_priv, sizeof(*file_priv), DRM_MEM_FILES);
489
490         /* ========================================================
491          * End inline drm_release
492          */
493
494         atomic_inc(&dev->counts[_DRM_STAT_CLOSES]);
495         spin_lock(&dev->count_lock);
496         if (!--dev->open_count) {
497                 if (atomic_read(&dev->ioctl_count)) {
498                         DRM_ERROR("Device busy: %d\n",
499                                   atomic_read(&dev->ioctl_count));
500                         spin_unlock(&dev->count_lock);
501                         unlock_kernel();
502                         return -EBUSY;
503                 }
504                 spin_unlock(&dev->count_lock);
505                 unlock_kernel();
506                 return drm_lastclose(dev);
507         }
508         spin_unlock(&dev->count_lock);
509
510         unlock_kernel();
511
512         return retcode;
513 }
514 EXPORT_SYMBOL(drm_release);
515
516 /** No-op. */
517 /* This is to deal with older X servers that believe 0 means data is
518  * available which is not the correct return for a poll function.
519  * This cannot be fixed until the Xserver is fixed. Xserver will need
520  * to set a newer interface version to avoid breaking older Xservers.
521  * Without fixing the Xserver you get: "WaitForSomething(): select: errno=22"
522  * http://freedesktop.org/bugzilla/show_bug.cgi?id=1505 if you try
523  * to return the correct response.
524  */
525 unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait)
526 {
527         /* return (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM); */
528         return 0;
529 }
530 EXPORT_SYMBOL(drm_poll);