gdb - Local mods (compile)
[dragonfly.git] / sys / dev / drm / 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 <sys/types.h>
38 #include <sys/conf.h>
39 #include <sys/devfs.h>
40
41 #include <drm/drmP.h>
42 #include <linux/module.h>
43 #include "drm_legacy.h"
44 #include "drm_internal.h"
45
46 /* from BKL pushdown: note that nothing else serializes idr_find() */
47 DEFINE_MUTEX(drm_global_mutex);
48 EXPORT_SYMBOL(drm_global_mutex);
49
50 extern drm_pci_id_list_t *drm_find_description(int vendor, int device,
51     drm_pci_id_list_t *idlist);
52 extern devclass_t drm_devclass;
53
54 static int drm_setup(struct drm_device *dev)
55 {
56         drm_local_map_t *map;
57         int i;
58
59         DRM_LOCK_ASSERT(dev);
60
61         /* prebuild the SAREA */
62         i = drm_legacy_addmap(dev, 0, SAREA_MAX, _DRM_SHM,
63             _DRM_CONTAINS_LOCK, &map);
64         if (i != 0)
65                 return i;
66
67         if (dev->driver->firstopen)
68                 dev->driver->firstopen(dev);
69
70         dev->buf_use = 0;
71
72         if (drm_core_check_feature(dev, DRIVER_HAVE_DMA)) {
73                 i = drm_legacy_dma_setup(dev);
74                 if (i != 0)
75                         return i;
76         }
77
78         drm_ht_create(&dev->magiclist, DRM_MAGIC_HASH_ORDER);
79         INIT_LIST_HEAD(&dev->magicfree);
80
81         init_waitqueue_head(&dev->lock.lock_queue);
82         if (!drm_core_check_feature(dev, DRIVER_MODESET))
83                 dev->irq_enabled = 0;
84         dev->context_flag = 0;
85         dev->last_context = 0;
86         dev->if_version = 0;
87
88         dev->buf_sigio = NULL;
89
90         DRM_DEBUG("\n");
91
92         return 0;
93 }
94
95 #define DRIVER_SOFTC(unit) \
96         ((struct drm_device *)devclass_get_softc(drm_devclass, unit))
97
98 int
99 drm_open(struct dev_open_args *ap)
100 {
101         struct cdev *kdev = ap->a_head.a_dev;
102         int flags = ap->a_oflags;
103         int fmt = 0;
104         struct thread *p = curthread;
105         struct drm_device *dev;
106         int retcode;
107
108         dev = DRIVER_SOFTC(minor(kdev));
109         if (dev == NULL)
110                 return (ENXIO);
111
112         DRM_DEBUG("open_count = %d\n", dev->open_count);
113
114         retcode = drm_open_helper(kdev, flags, fmt, p, dev, ap->a_fp);
115
116         if (retcode == 0) {
117                 atomic_inc(&dev->counts[_DRM_STAT_OPENS]);
118                 DRM_LOCK(dev);
119                 device_busy(dev->dev);
120                 if (!dev->open_count++)
121                         retcode = drm_setup(dev);
122                 DRM_UNLOCK(dev);
123         }
124
125         DRM_DEBUG("return %d\n", retcode);
126
127         return (retcode);
128 }
129
130 /* drm_open_helper is called whenever a process opens /dev/drm. */
131 int drm_open_helper(struct cdev *kdev, int flags, int fmt, DRM_STRUCTPROC *p,
132                     struct drm_device *dev, struct file *fp)
133 {
134         struct drm_file *priv;
135         int retcode;
136
137         if (flags & O_EXCL)
138                 return EBUSY; /* No exclusive opens */
139         dev->flags = flags;
140
141         DRM_DEBUG("pid = %d, device = %s\n", DRM_CURRENTPID, devtoname(kdev));
142
143         priv = kmalloc(sizeof(*priv), M_DRM, M_WAITOK | M_NULLOK | M_ZERO);
144         if (priv == NULL) {
145                 return ENOMEM;
146         }
147         
148         DRM_LOCK(dev);
149         priv->dev               = dev;
150         priv->uid               = p->td_proc->p_ucred->cr_svuid;
151         priv->pid               = p->td_proc->p_pid;
152
153         /* for compatibility root is always authenticated */
154         priv->authenticated = capable(CAP_SYS_ADMIN);
155
156         INIT_LIST_HEAD(&priv->fbs);
157         INIT_LIST_HEAD(&priv->event_list);
158         init_waitqueue_head(&priv->event_wait);
159         priv->event_space = 4096; /* set aside 4k for event buffer */
160
161         if (drm_core_check_feature(dev, DRIVER_GEM))
162                 drm_gem_open(dev, priv);
163
164         if (dev->driver->open) {
165                 /* shared code returns -errno */
166                 retcode = -dev->driver->open(dev, priv);
167                 if (retcode != 0) {
168                         drm_free(priv, M_DRM);
169                         DRM_UNLOCK(dev);
170                         return retcode;
171                 }
172         }
173
174         /* first opener automatically becomes master */
175         priv->master = list_empty(&dev->filelist);
176
177         list_add(&priv->lhead, &dev->filelist);
178         DRM_UNLOCK(dev);
179         kdev->si_drv1 = dev;
180
181         retcode = devfs_set_cdevpriv(fp, priv, &drm_cdevpriv_dtor);
182         if (retcode != 0)
183                 drm_cdevpriv_dtor(priv);
184
185         return retcode;
186 }
187
188 /**
189  * Release file.
190  *
191  * \param inode device inode
192  * \param file_priv DRM file private.
193  * \return zero on success or a negative number on failure.
194  *
195  * If the hardware lock is held then free it, and take it again for the kernel
196  * context since it's necessary to reclaim buffers. Unlink the file private
197  * data from its list and free it. Decreases the open count and if it reaches
198  * zero calls drm_lastclose().
199  */
200
201 static void drm_unload(struct drm_device *dev)
202 {
203         int i;
204
205         DRM_DEBUG("\n");
206
207         drm_sysctl_cleanup(dev);
208         if (dev->devnode != NULL)
209                 destroy_dev(dev->devnode);
210
211         if (drm_core_check_feature(dev, DRIVER_GEM))
212                 drm_gem_destroy(dev);
213
214         if (dev->agp && dev->agp->agp_mtrr) {
215                 int __unused retcode;
216
217                 retcode = drm_mtrr_del(0, dev->agp->agp_info.ai_aperture_base,
218                     dev->agp->agp_info.ai_aperture_size, DRM_MTRR_WC);
219                 DRM_DEBUG("mtrr_del = %d", retcode);
220         }
221
222         drm_vblank_cleanup(dev);
223
224         DRM_LOCK(dev);
225         drm_lastclose(dev);
226         DRM_UNLOCK(dev);
227
228         /* Clean up PCI resources allocated by drm_bufs.c.  We're not really
229          * worried about resource consumption while the DRM is inactive (between
230          * lastclose and firstopen or unload) because these aren't actually
231          * taking up KVA, just keeping the PCI resource allocated.
232          */
233         for (i = 0; i < DRM_MAX_PCI_RESOURCE; i++) {
234                 if (dev->pcir[i] == NULL)
235                         continue;
236                 bus_release_resource(dev->dev, SYS_RES_MEMORY,
237                     dev->pcirid[i], dev->pcir[i]);
238                 dev->pcir[i] = NULL;
239         }
240
241         if (dev->agp) {
242                 drm_free(dev->agp, M_DRM);
243                 dev->agp = NULL;
244         }
245
246         if (dev->driver->unload != NULL) {
247                 DRM_LOCK(dev);
248                 dev->driver->unload(dev);
249                 DRM_UNLOCK(dev);
250         }
251
252         drm_mem_uninit();
253
254         if (pci_disable_busmaster(dev->dev))
255                 DRM_ERROR("Request to disable bus-master failed.\n");
256
257         lockuninit(&dev->vbl_lock);
258         lockuninit(&dev->dev_lock);
259         lockuninit(&dev->event_lock);
260         lockuninit(&dev->struct_mutex);
261 }
262
263 /**
264  * Take down the DRM device.
265  *
266  * \param dev DRM device structure.
267  *
268  * Frees every resource in \p dev.
269  *
270  * \sa drm_device
271  */
272 int drm_lastclose(struct drm_device * dev)
273 {
274         DRM_DEBUG("\n");
275
276         if (dev->driver->lastclose)
277                 dev->driver->lastclose(dev);
278         DRM_DEBUG("driver lastclose completed\n");
279
280         if (dev->irq_enabled && !drm_core_check_feature(dev, DRIVER_MODESET))
281                 drm_irq_uninstall(dev);
282
283         mutex_lock(&dev->struct_mutex);
284
285         if (dev->unique) {
286                 drm_free(dev->unique, M_DRM);
287                 dev->unique = NULL;
288                 dev->unique_len = 0;
289         }
290
291         /* Clear AGP information */
292         if (dev->agp) {
293                 drm_agp_mem_t *entry;
294                 drm_agp_mem_t *nexte;
295
296                 /* Remove AGP resources, but leave dev->agp intact until
297                  * drm_unload is called.
298                  */
299                 for (entry = dev->agp->memory; entry; entry = nexte) {
300                         nexte = entry->next;
301                         if (entry->bound)
302                                 drm_agp_unbind_memory(entry->handle);
303                         drm_agp_free_memory(entry->handle);
304                         drm_free(entry, M_DRM);
305                 }
306                 dev->agp->memory = NULL;
307
308                 if (dev->agp->acquired)
309                         drm_agp_release(dev);
310
311                 dev->agp->acquired = 0;
312                 dev->agp->enabled  = 0;
313         }
314         if (dev->sg != NULL) {
315                 drm_legacy_sg_cleanup(dev->sg);
316                 dev->sg = NULL;
317         }
318
319         drm_legacy_dma_takedown(dev);
320
321         if (dev->lock.hw_lock) {
322                 dev->lock.hw_lock = NULL; /* SHM removed */
323                 dev->lock.file_priv = NULL;
324                 wakeup(&dev->lock.lock_queue);
325         }
326
327         mutex_unlock(&dev->struct_mutex);
328
329         DRM_DEBUG("lastclose completed\n");
330         return 0;
331 }
332
333 /**
334  * Release file.
335  *
336  * \param inode device inode
337  * \param file_priv DRM file private.
338  * \return zero on success or a negative number on failure.
339  *
340  * If the hardware lock is held then free it, and take it again for the kernel
341  * context since it's necessary to reclaim buffers. Unlink the file private
342  * data from its list and free it. Decreases the open count and if it reaches
343  * zero calls drm_lastclose().
344  */
345 int drm_release(device_t kdev)
346 {
347         struct drm_device *dev = device_get_softc(kdev);
348         struct drm_magic_entry *pt, *next;
349
350         mutex_lock(&drm_global_mutex);
351
352         /* Clear pid list */
353         if (dev->magicfree.next) {
354                 list_for_each_entry_safe(pt, next, &dev->magicfree, head) {
355                         list_del(&pt->head);
356                         drm_ht_remove_item(&dev->magiclist, &pt->hash_item);
357                         kfree(pt);
358                 }
359                 drm_ht_remove(&dev->magiclist);
360         }
361
362         drm_unload(dev);
363         if (dev->irqr) {
364                 bus_release_resource(dev->dev, SYS_RES_IRQ, dev->irqrid,
365                     dev->irqr);
366                 if (dev->irq_type == PCI_INTR_TYPE_MSI) {
367                         pci_release_msi(dev->dev);
368                         DRM_INFO("MSI released\n");
369                 }
370         }
371
372         mutex_unlock(&drm_global_mutex);
373
374         return (0);
375 }
376
377 static bool
378 drm_dequeue_event(struct drm_device *dev, struct drm_file *file_priv,
379     struct uio *uio, struct drm_pending_event **out)
380 {
381         struct drm_pending_event *e;
382         bool ret = false;
383
384         lockmgr(&dev->event_lock, LK_EXCLUSIVE);
385
386         *out = NULL;
387         if (list_empty(&file_priv->event_list))
388                 goto out;
389         e = list_first_entry(&file_priv->event_list,
390             struct drm_pending_event, link);
391         if (e->event->length > uio->uio_resid)
392                 goto out;
393
394         file_priv->event_space += e->event->length;
395         list_del(&e->link);
396         *out = e;
397         ret = true;
398
399 out:
400         lockmgr(&dev->event_lock, LK_RELEASE);
401         return ret;
402 }
403
404 int
405 drm_read(struct dev_read_args *ap)
406 {
407         struct cdev *kdev = ap->a_head.a_dev;
408         struct uio *uio = ap->a_uio;
409         struct drm_file *file_priv;
410         struct drm_device *dev = drm_get_device_from_kdev(kdev);
411         struct drm_pending_event *e;
412         int error;
413         int ret;
414
415         error = devfs_get_cdevpriv(ap->a_fp, (void **)&file_priv);
416         if (error != 0) {
417                 DRM_ERROR("can't find authenticator\n");
418                 return (EINVAL);
419         }
420
421         ret = wait_event_interruptible(file_priv->event_wait,
422                                        !list_empty(&file_priv->event_list));
423         if (ret == -ERESTARTSYS)
424                 ret = -EINTR;
425         if (ret < 0)
426                 return -ret;
427
428         while (drm_dequeue_event(dev, file_priv, uio, &e)) {
429                 error = uiomove((caddr_t)e->event, e->event->length, uio);
430                 e->destroy(e);
431                 if (error != 0)
432                         return (error);
433         }
434
435         return (error);
436 }
437
438 static int
439 drmfilt(struct knote *kn, long hint)
440 {
441         struct drm_file *file_priv;
442         struct drm_device *dev;
443         int ready = 0;
444
445         file_priv = (struct drm_file *)kn->kn_hook;
446         dev = file_priv->dev;
447         lockmgr(&dev->event_lock, LK_EXCLUSIVE);
448         if (!list_empty(&file_priv->event_list))
449                 ready = 1;
450         lockmgr(&dev->event_lock, LK_RELEASE);
451
452         return (ready);
453 }
454
455 static void
456 drmfilt_detach(struct knote *kn)
457 {
458         struct drm_file *file_priv;
459         struct drm_device *dev;
460         struct klist *klist;
461
462         file_priv = (struct drm_file *)kn->kn_hook;
463         dev = file_priv->dev;
464
465         klist = &file_priv->dkq.ki_note;
466         knote_remove(klist, kn);
467 }
468
469 static struct filterops drmfiltops =
470         { FILTEROP_MPSAFE | FILTEROP_ISFD, NULL, drmfilt_detach, drmfilt };
471
472 int
473 drm_kqfilter(struct dev_kqfilter_args *ap)
474 {
475         struct cdev *kdev = ap->a_head.a_dev;
476         struct drm_file *file_priv;
477         struct drm_device *dev;
478         struct knote *kn = ap->a_kn;
479         struct klist *klist;
480         int error;
481
482         error = devfs_get_cdevpriv(ap->a_fp, (void **)&file_priv);
483         if (error != 0) {
484                 DRM_ERROR("can't find authenticator\n");
485                 return (EINVAL);
486         }
487         dev = drm_get_device_from_kdev(kdev);
488
489         ap->a_result = 0;
490
491         switch (kn->kn_filter) {
492         case EVFILT_READ:
493         case EVFILT_WRITE:
494                 kn->kn_fop = &drmfiltops;
495                 kn->kn_hook = (caddr_t)file_priv;
496                 break;
497         default:
498                 ap->a_result = EOPNOTSUPP;
499                 return (0);
500         }
501
502         klist = &file_priv->dkq.ki_note;
503         knote_insert(klist, kn);
504
505         return (0);
506 }