aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_fops.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2008-05-28 20:09:59 -0400
committerDave Airlie <airlied@redhat.com>2008-07-13 20:45:01 -0400
commitc0e09200dc0813972442e550a5905a132768e56c (patch)
treed38e635a30ff8b0a2b98b9d7f97cab1501f8209e /drivers/gpu/drm/drm_fops.c
parentbce7f793daec3e65ec5c5705d2457b81fe7b5725 (diff)
drm: reorganise drm tree to be more future proof.
With the coming of kernel based modesetting and the memory manager stuff, the everything in one directory approach was getting very ugly and starting to be unmanageable. This restructures the drm along the lines of other kernel components. It creates a drivers/gpu/drm directory and moves the hw drivers into subdirectores. It moves the includes into an include/drm, and sets up the unifdef for the userspace headers we should be exporting. 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.c466
1 files changed, 466 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
new file mode 100644
index 000000000000..d2e6da85f58a
--- /dev/null
+++ b/drivers/gpu/drm/drm_fops.c
@@ -0,0 +1,466 @@
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
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 drm_local_map_t *map;
47 int i;
48 int ret;
49 u32 sareapage;
50
51 if (dev->driver->firstopen) {
52 ret = dev->driver->firstopen(dev);
53 if (ret != 0)
54 return ret;
55 }
56
57 dev->magicfree.next = NULL;
58
59 /* prebuild the SAREA */
60 sareapage = max_t(unsigned, SAREA_MAX, PAGE_SIZE);
61 i = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK, &map);
62 if (i != 0)
63 return i;
64
65 atomic_set(&dev->ioctl_count, 0);
66 atomic_set(&dev->vma_count, 0);
67 dev->buf_use = 0;
68 atomic_set(&dev->buf_alloc, 0);
69
70 if (drm_core_check_feature(dev, DRIVER_HAVE_DMA)) {
71 i = drm_dma_setup(dev);
72 if (i < 0)
73 return i;
74 }
75
76 for (i = 0; i < ARRAY_SIZE(dev->counts); i++)
77 atomic_set(&dev->counts[i], 0);
78
79 drm_ht_create(&dev->magiclist, DRM_MAGIC_HASH_ORDER);
80 INIT_LIST_HEAD(&dev->magicfree);
81
82 dev->sigdata.lock = NULL;
83 init_waitqueue_head(&dev->lock.lock_queue);
84 dev->queue_count = 0;
85 dev->queue_reserved = 0;
86 dev->queue_slots = 0;
87 dev->queuelist = NULL;
88 dev->irq_enabled = 0;
89 dev->context_flag = 0;
90 dev->interrupt_flag = 0;
91 dev->dma_flag = 0;
92 dev->last_context = 0;
93 dev->last_switch = 0;
94 dev->last_checked = 0;
95 init_waitqueue_head(&dev->context_wait);
96 dev->if_version = 0;
97
98 dev->ctx_start = 0;
99 dev->lck_start = 0;
100
101 dev->buf_async = NULL;
102 init_waitqueue_head(&dev->buf_readers);
103 init_waitqueue_head(&dev->buf_writers);
104
105 DRM_DEBUG("\n");
106
107 /*
108 * The kernel's context could be created here, but is now created
109 * in drm_dma_enqueue. This is more resource-efficient for
110 * hardware that does not do DMA, but may mean that
111 * drm_select_queue fails between the time the interrupt is
112 * initialized and the time the queues are initialized.
113 */
114
115 return 0;
116}
117
118/**
119 * Open file.
120 *
121 * \param inode device inode
122 * \param filp file pointer.
123 * \return zero on success or a negative number on failure.
124 *
125 * Searches the DRM device with the same minor number, calls open_helper(), and
126 * increments the device open count. If the open count was previous at zero,
127 * i.e., it's the first that the device is open, then calls setup().
128 */
129int drm_open(struct inode *inode, struct file *filp)
130{
131 struct drm_device *dev = NULL;
132 int minor_id = iminor(inode);
133 struct drm_minor *minor;
134 int retcode = 0;
135
136 minor = idr_find(&drm_minors_idr, minor_id);
137 if (!minor)
138 return -ENODEV;
139
140 if (!(dev = minor->dev))
141 return -ENODEV;
142
143 retcode = drm_open_helper(inode, filp, dev);
144 if (!retcode) {
145 atomic_inc(&dev->counts[_DRM_STAT_OPENS]);
146 spin_lock(&dev->count_lock);
147 if (!dev->open_count++) {
148 spin_unlock(&dev->count_lock);
149 return drm_setup(dev);
150 }
151 spin_unlock(&dev->count_lock);
152 }
153
154 return retcode;
155}
156EXPORT_SYMBOL(drm_open);
157
158/**
159 * File \c open operation.
160 *
161 * \param inode device inode.
162 * \param filp file pointer.
163 *
164 * Puts the dev->fops corresponding to the device minor number into
165 * \p filp, call the \c open method, and restore the file operations.
166 */
167int drm_stub_open(struct inode *inode, struct file *filp)
168{
169 struct drm_device *dev = NULL;
170 struct drm_minor *minor;
171 int minor_id = iminor(inode);
172 int err = -ENODEV;
173 const struct file_operations *old_fops;
174
175 DRM_DEBUG("\n");
176
177 minor = idr_find(&drm_minors_idr, minor_id);
178 if (!minor)
179 return -ENODEV;
180
181 if (!(dev = minor->dev))
182 return -ENODEV;
183
184 old_fops = filp->f_op;
185 filp->f_op = fops_get(&dev->driver->fops);
186 if (filp->f_op->open && (err = filp->f_op->open(inode, filp))) {
187 fops_put(filp->f_op);
188 filp->f_op = fops_get(old_fops);
189 }
190 fops_put(old_fops);
191
192 return err;
193}
194
195/**
196 * Check whether DRI will run on this CPU.
197 *
198 * \return non-zero if the DRI will run on this CPU, or zero otherwise.
199 */
200static int drm_cpu_valid(void)
201{
202#if defined(__i386__)
203 if (boot_cpu_data.x86 == 3)
204 return 0; /* No cmpxchg on a 386 */
205#endif
206#if defined(__sparc__) && !defined(__sparc_v9__)
207 return 0; /* No cmpxchg before v9 sparc. */
208#endif
209 return 1;
210}
211
212/**
213 * Called whenever a process opens /dev/drm.
214 *
215 * \param inode device inode.
216 * \param filp file pointer.
217 * \param dev device.
218 * \return zero on success or a negative number on failure.
219 *
220 * Creates and initializes a drm_file structure for the file private data in \p
221 * filp and add it into the double linked list in \p dev.
222 */
223static int drm_open_helper(struct inode *inode, struct file *filp,
224 struct drm_device * dev)
225{
226 int minor_id = iminor(inode);
227 struct drm_file *priv;
228 int ret;
229
230 if (filp->f_flags & O_EXCL)
231 return -EBUSY; /* No exclusive opens */
232 if (!drm_cpu_valid())
233 return -EINVAL;
234
235 DRM_DEBUG("pid = %d, minor = %d\n", task_pid_nr(current), minor_id);
236
237 priv = drm_alloc(sizeof(*priv), DRM_MEM_FILES);
238 if (!priv)
239 return -ENOMEM;
240
241 memset(priv, 0, sizeof(*priv));
242 filp->private_data = priv;
243 priv->filp = filp;
244 priv->uid = current->euid;
245 priv->pid = task_pid_nr(current);
246 priv->minor = idr_find(&drm_minors_idr, minor_id);
247 priv->ioctl_count = 0;
248 /* for compatibility root is always authenticated */
249 priv->authenticated = capable(CAP_SYS_ADMIN);
250 priv->lock_count = 0;
251
252 INIT_LIST_HEAD(&priv->lhead);
253
254 if (dev->driver->open) {
255 ret = dev->driver->open(dev, priv);
256 if (ret < 0)
257 goto out_free;
258 }
259
260 mutex_lock(&dev->struct_mutex);
261 if (list_empty(&dev->filelist))
262 priv->master = 1;
263
264 list_add(&priv->lhead, &dev->filelist);
265 mutex_unlock(&dev->struct_mutex);
266
267#ifdef __alpha__
268 /*
269 * Default the hose
270 */
271 if (!dev->hose) {
272 struct pci_dev *pci_dev;
273 pci_dev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, NULL);
274 if (pci_dev) {
275 dev->hose = pci_dev->sysdata;
276 pci_dev_put(pci_dev);
277 }
278 if (!dev->hose) {
279 struct pci_bus *b = pci_bus_b(pci_root_buses.next);
280 if (b)
281 dev->hose = b->sysdata;
282 }
283 }
284#endif
285
286 return 0;
287 out_free:
288 drm_free(priv, sizeof(*priv), DRM_MEM_FILES);
289 filp->private_data = NULL;
290 return ret;
291}
292
293/** No-op. */
294int drm_fasync(int fd, struct file *filp, int on)
295{
296 struct drm_file *priv = filp->private_data;
297 struct drm_device *dev = priv->minor->dev;
298 int retcode;
299
300 DRM_DEBUG("fd = %d, device = 0x%lx\n", fd,
301 (long)old_encode_dev(priv->minor->device));
302 retcode = fasync_helper(fd, filp, on, &dev->buf_async);
303 if (retcode < 0)
304 return retcode;
305 return 0;
306}
307EXPORT_SYMBOL(drm_fasync);
308
309/**
310 * Release file.
311 *
312 * \param inode device inode
313 * \param file_priv DRM file private.
314 * \return zero on success or a negative number on failure.
315 *
316 * If the hardware lock is held then free it, and take it again for the kernel
317 * context since it's necessary to reclaim buffers. Unlink the file private
318 * data from its list and free it. Decreases the open count and if it reaches
319 * zero calls drm_lastclose().
320 */
321int drm_release(struct inode *inode, struct file *filp)
322{
323 struct drm_file *file_priv = filp->private_data;
324 struct drm_device *dev = file_priv->minor->dev;
325 int retcode = 0;
326
327 lock_kernel();
328
329 DRM_DEBUG("open_count = %d\n", dev->open_count);
330
331 if (dev->driver->preclose)
332 dev->driver->preclose(dev, file_priv);
333
334 /* ========================================================
335 * Begin inline drm_release
336 */
337
338 DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n",
339 task_pid_nr(current),
340 (long)old_encode_dev(file_priv->minor->device),
341 dev->open_count);
342
343 if (dev->driver->reclaim_buffers_locked && dev->lock.hw_lock) {
344 if (drm_i_have_hw_lock(dev, file_priv)) {
345 dev->driver->reclaim_buffers_locked(dev, file_priv);
346 } else {
347 unsigned long endtime = jiffies + 3 * DRM_HZ;
348 int locked = 0;
349
350 drm_idlelock_take(&dev->lock);
351
352 /*
353 * Wait for a while.
354 */
355
356 do{
357 spin_lock_bh(&dev->lock.spinlock);
358 locked = dev->lock.idle_has_lock;
359 spin_unlock_bh(&dev->lock.spinlock);
360 if (locked)
361 break;
362 schedule();
363 } while (!time_after_eq(jiffies, endtime));
364
365 if (!locked) {
366 DRM_ERROR("reclaim_buffers_locked() deadlock. Please rework this\n"
367 "\tdriver to use reclaim_buffers_idlelocked() instead.\n"
368 "\tI will go on reclaiming the buffers anyway.\n");
369 }
370
371 dev->driver->reclaim_buffers_locked(dev, file_priv);
372 drm_idlelock_release(&dev->lock);
373 }
374 }
375
376 if (dev->driver->reclaim_buffers_idlelocked && dev->lock.hw_lock) {
377
378 drm_idlelock_take(&dev->lock);
379 dev->driver->reclaim_buffers_idlelocked(dev, file_priv);
380 drm_idlelock_release(&dev->lock);
381
382 }
383
384 if (drm_i_have_hw_lock(dev, file_priv)) {
385 DRM_DEBUG("File %p released, freeing lock for context %d\n",
386 filp, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
387
388 drm_lock_free(&dev->lock,
389 _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
390 }
391
392
393 if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) &&
394 !dev->driver->reclaim_buffers_locked) {
395 dev->driver->reclaim_buffers(dev, file_priv);
396 }
397
398 drm_fasync(-1, filp, 0);
399
400 mutex_lock(&dev->ctxlist_mutex);
401 if (!list_empty(&dev->ctxlist)) {
402 struct drm_ctx_list *pos, *n;
403
404 list_for_each_entry_safe(pos, n, &dev->ctxlist, head) {
405 if (pos->tag == file_priv &&
406 pos->handle != DRM_KERNEL_CONTEXT) {
407 if (dev->driver->context_dtor)
408 dev->driver->context_dtor(dev,
409 pos->handle);
410
411 drm_ctxbitmap_free(dev, pos->handle);
412
413 list_del(&pos->head);
414 drm_free(pos, sizeof(*pos), DRM_MEM_CTXLIST);
415 --dev->ctx_count;
416 }
417 }
418 }
419 mutex_unlock(&dev->ctxlist_mutex);
420
421 mutex_lock(&dev->struct_mutex);
422 if (file_priv->remove_auth_on_close == 1) {
423 struct drm_file *temp;
424
425 list_for_each_entry(temp, &dev->filelist, lhead)
426 temp->authenticated = 0;
427 }
428 list_del(&file_priv->lhead);
429 mutex_unlock(&dev->struct_mutex);
430
431 if (dev->driver->postclose)
432 dev->driver->postclose(dev, file_priv);
433 drm_free(file_priv, sizeof(*file_priv), DRM_MEM_FILES);
434
435 /* ========================================================
436 * End inline drm_release
437 */
438
439 atomic_inc(&dev->counts[_DRM_STAT_CLOSES]);
440 spin_lock(&dev->count_lock);
441 if (!--dev->open_count) {
442 if (atomic_read(&dev->ioctl_count) || dev->blocked) {
443 DRM_ERROR("Device busy: %d %d\n",
444 atomic_read(&dev->ioctl_count), dev->blocked);
445 spin_unlock(&dev->count_lock);
446 unlock_kernel();
447 return -EBUSY;
448 }
449 spin_unlock(&dev->count_lock);
450 unlock_kernel();
451 return drm_lastclose(dev);
452 }
453 spin_unlock(&dev->count_lock);
454
455 unlock_kernel();
456
457 return retcode;
458}
459EXPORT_SYMBOL(drm_release);
460
461/** No-op. */
462unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait)
463{
464 return 0;
465}
466EXPORT_SYMBOL(drm_poll);