~ubuntu-branches/ubuntu/maverick/linux-backports-modules-2.6.32/maverick

« back to all changes in this revision

Viewing changes to updates/nouveau/drm_irq.c

  • Committer: Bazaar Package Importer
  • Author(s): Andy Whitcroft, Andy Whitcroft
  • Date: 2010-02-04 23:15:51 UTC
  • Revision ID: james.westby@ubuntu.com-20100204231551-vjz5pkvxclukjxm1
Tags: 2.6.32-12.1
[ Andy Whitcroft ]

* initial LBM for lucid
* drop generated files
* printchanges -- rebase tree does not have stable tags use changelog
* printenv -- add revisions to printenv output
* formally rename compat-wireless to linux-backports-modules-wireless
* Update to compat-wireless-2.6.33-rc5
* update nouveau to mainline 2.6.33-rc4
* add new LBM package for nouveau
* nouveau -- fix major numbers and proc entry names
* fix up firmware installs for -wireless
* clean up UPDATE-NOVEAU
* update Nouveau to v2.6.33-rc6

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * \file drm_irq.c
 
3
 * IRQ support
 
4
 *
 
5
 * \author Rickard E. (Rik) Faith <faith@valinux.com>
 
6
 * \author Gareth Hughes <gareth@valinux.com>
 
7
 */
 
8
 
 
9
/*
 
10
 * Created: Fri Mar 19 14:30:16 1999 by faith@valinux.com
 
11
 *
 
12
 * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
 
13
 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
 
14
 * All Rights Reserved.
 
15
 *
 
16
 * Permission is hereby granted, free of charge, to any person obtaining a
 
17
 * copy of this software and associated documentation files (the "Software"),
 
18
 * to deal in the Software without restriction, including without limitation
 
19
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 
20
 * and/or sell copies of the Software, and to permit persons to whom the
 
21
 * Software is furnished to do so, subject to the following conditions:
 
22
 *
 
23
 * The above copyright notice and this permission notice (including the next
 
24
 * paragraph) shall be included in all copies or substantial portions of the
 
25
 * Software.
 
26
 *
 
27
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
28
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
29
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 
30
 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 
31
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 
32
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 
33
 * OTHER DEALINGS IN THE SOFTWARE.
 
34
 */
 
35
 
 
36
#include "drmP.h"
 
37
 
 
38
#include <linux/interrupt.h>    /* For task queue support */
 
39
 
 
40
#include <linux/vgaarb.h>
 
41
/**
 
42
 * Get interrupt from bus id.
 
43
 *
 
44
 * \param inode device inode.
 
45
 * \param file_priv DRM file private.
 
46
 * \param cmd command.
 
47
 * \param arg user argument, pointing to a drm_irq_busid structure.
 
48
 * \return zero on success or a negative number on failure.
 
49
 *
 
50
 * Finds the PCI device with the specified bus id and gets its IRQ number.
 
51
 * This IOCTL is deprecated, and will now return EINVAL for any busid not equal
 
52
 * to that of the device that this DRM instance attached to.
 
53
 */
 
54
int drm_irq_by_busid(struct drm_device *dev, void *data,
 
55
                     struct drm_file *file_priv)
 
56
{
 
57
        struct drm_irq_busid *p = data;
 
58
 
 
59
        if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
 
60
                return -EINVAL;
 
61
 
 
62
        if ((p->busnum >> 8) != drm_get_pci_domain(dev) ||
 
63
            (p->busnum & 0xff) != dev->pdev->bus->number ||
 
64
            p->devnum != PCI_SLOT(dev->pdev->devfn) || p->funcnum != PCI_FUNC(dev->pdev->devfn))
 
65
                return -EINVAL;
 
66
 
 
67
        p->irq = dev->pdev->irq;
 
68
 
 
69
        DRM_DEBUG("%d:%d:%d => IRQ %d\n", p->busnum, p->devnum, p->funcnum,
 
70
                  p->irq);
 
71
 
 
72
        return 0;
 
73
}
 
74
 
 
75
static void vblank_disable_fn(unsigned long arg)
 
76
{
 
77
        struct drm_device *dev = (struct drm_device *)arg;
 
78
        unsigned long irqflags;
 
79
        int i;
 
80
 
 
81
        if (!dev->vblank_disable_allowed)
 
82
                return;
 
83
 
 
84
        for (i = 0; i < dev->num_crtcs; i++) {
 
85
                spin_lock_irqsave(&dev->vbl_lock, irqflags);
 
86
                if (atomic_read(&dev->vblank_refcount[i]) == 0 &&
 
87
                    dev->vblank_enabled[i]) {
 
88
                        DRM_DEBUG("disabling vblank on crtc %d\n", i);
 
89
                        dev->last_vblank[i] =
 
90
                                dev->driver->get_vblank_counter(dev, i);
 
91
                        dev->driver->disable_vblank(dev, i);
 
92
                        dev->vblank_enabled[i] = 0;
 
93
                }
 
94
                spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
 
95
        }
 
96
}
 
97
 
 
98
void drm_vblank_cleanup(struct drm_device *dev)
 
99
{
 
100
        /* Bail if the driver didn't call drm_vblank_init() */
 
101
        if (dev->num_crtcs == 0)
 
102
                return;
 
103
 
 
104
        del_timer(&dev->vblank_disable_timer);
 
105
 
 
106
        vblank_disable_fn((unsigned long)dev);
 
107
 
 
108
        kfree(dev->vbl_queue);
 
109
        kfree(dev->_vblank_count);
 
110
        kfree(dev->vblank_refcount);
 
111
        kfree(dev->vblank_enabled);
 
112
        kfree(dev->last_vblank);
 
113
        kfree(dev->last_vblank_wait);
 
114
        kfree(dev->vblank_inmodeset);
 
115
 
 
116
        dev->num_crtcs = 0;
 
117
}
 
118
EXPORT_SYMBOL(drm_vblank_cleanup);
 
119
 
 
120
int drm_vblank_init(struct drm_device *dev, int num_crtcs)
 
121
{
 
122
        int i, ret = -ENOMEM;
 
123
 
 
124
        setup_timer(&dev->vblank_disable_timer, vblank_disable_fn,
 
125
                    (unsigned long)dev);
 
126
        spin_lock_init(&dev->vbl_lock);
 
127
        dev->num_crtcs = num_crtcs;
 
128
 
 
129
        dev->vbl_queue = kmalloc(sizeof(wait_queue_head_t) * num_crtcs,
 
130
                                 GFP_KERNEL);
 
131
        if (!dev->vbl_queue)
 
132
                goto err;
 
133
 
 
134
        dev->_vblank_count = kmalloc(sizeof(atomic_t) * num_crtcs, GFP_KERNEL);
 
135
        if (!dev->_vblank_count)
 
136
                goto err;
 
137
 
 
138
        dev->vblank_refcount = kmalloc(sizeof(atomic_t) * num_crtcs,
 
139
                                       GFP_KERNEL);
 
140
        if (!dev->vblank_refcount)
 
141
                goto err;
 
142
 
 
143
        dev->vblank_enabled = kcalloc(num_crtcs, sizeof(int), GFP_KERNEL);
 
144
        if (!dev->vblank_enabled)
 
145
                goto err;
 
146
 
 
147
        dev->last_vblank = kcalloc(num_crtcs, sizeof(u32), GFP_KERNEL);
 
148
        if (!dev->last_vblank)
 
149
                goto err;
 
150
 
 
151
        dev->last_vblank_wait = kcalloc(num_crtcs, sizeof(u32), GFP_KERNEL);
 
152
        if (!dev->last_vblank_wait)
 
153
                goto err;
 
154
 
 
155
        dev->vblank_inmodeset = kcalloc(num_crtcs, sizeof(int), GFP_KERNEL);
 
156
        if (!dev->vblank_inmodeset)
 
157
                goto err;
 
158
 
 
159
        /* Zero per-crtc vblank stuff */
 
160
        for (i = 0; i < num_crtcs; i++) {
 
161
                init_waitqueue_head(&dev->vbl_queue[i]);
 
162
                atomic_set(&dev->_vblank_count[i], 0);
 
163
                atomic_set(&dev->vblank_refcount[i], 0);
 
164
        }
 
165
 
 
166
        dev->vblank_disable_allowed = 0;
 
167
        return 0;
 
168
 
 
169
err:
 
170
        drm_vblank_cleanup(dev);
 
171
        return ret;
 
172
}
 
173
EXPORT_SYMBOL(drm_vblank_init);
 
174
 
 
175
static void drm_irq_vgaarb_nokms(void *cookie, bool state)
 
176
{
 
177
        struct drm_device *dev = cookie;
 
178
 
 
179
        if (dev->driver->vgaarb_irq) {
 
180
                dev->driver->vgaarb_irq(dev, state);
 
181
                return;
 
182
        }
 
183
 
 
184
        if (!dev->irq_enabled)
 
185
                return;
 
186
 
 
187
        if (state)
 
188
                dev->driver->irq_uninstall(dev);
 
189
        else {
 
190
                dev->driver->irq_preinstall(dev);
 
191
                dev->driver->irq_postinstall(dev);
 
192
        }
 
193
}
 
194
 
 
195
/**
 
196
 * Install IRQ handler.
 
197
 *
 
198
 * \param dev DRM device.
 
199
 *
 
200
 * Initializes the IRQ related data. Installs the handler, calling the driver
 
201
 * \c drm_driver_irq_preinstall() and \c drm_driver_irq_postinstall() functions
 
202
 * before and after the installation.
 
203
 */
 
204
int drm_irq_install(struct drm_device *dev)
 
205
{
 
206
        int ret = 0;
 
207
        unsigned long sh_flags = 0;
 
208
        char *irqname;
 
209
 
 
210
        if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
 
211
                return -EINVAL;
 
212
 
 
213
        if (dev->pdev->irq == 0)
 
214
                return -EINVAL;
 
215
 
 
216
        mutex_lock(&dev->struct_mutex);
 
217
 
 
218
        /* Driver must have been initialized */
 
219
        if (!dev->dev_private) {
 
220
                mutex_unlock(&dev->struct_mutex);
 
221
                return -EINVAL;
 
222
        }
 
223
 
 
224
        if (dev->irq_enabled) {
 
225
                mutex_unlock(&dev->struct_mutex);
 
226
                return -EBUSY;
 
227
        }
 
228
        dev->irq_enabled = 1;
 
229
        mutex_unlock(&dev->struct_mutex);
 
230
 
 
231
        DRM_DEBUG("irq=%d\n", dev->pdev->irq);
 
232
 
 
233
        /* Before installing handler */
 
234
        dev->driver->irq_preinstall(dev);
 
235
 
 
236
        /* Install handler */
 
237
        if (drm_core_check_feature(dev, DRIVER_IRQ_SHARED))
 
238
                sh_flags = IRQF_SHARED;
 
239
 
 
240
        if (dev->devname)
 
241
                irqname = dev->devname;
 
242
        else
 
243
                irqname = dev->driver->name;
 
244
 
 
245
        ret = request_irq(drm_dev_to_irq(dev), dev->driver->irq_handler,
 
246
                          sh_flags, irqname, dev);
 
247
 
 
248
        if (ret < 0) {
 
249
                mutex_lock(&dev->struct_mutex);
 
250
                dev->irq_enabled = 0;
 
251
                mutex_unlock(&dev->struct_mutex);
 
252
                return ret;
 
253
        }
 
254
 
 
255
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
 
256
                vga_client_register(dev->pdev, (void *)dev, drm_irq_vgaarb_nokms, NULL);
 
257
 
 
258
        /* After installing handler */
 
259
        ret = dev->driver->irq_postinstall(dev);
 
260
        if (ret < 0) {
 
261
                mutex_lock(&dev->struct_mutex);
 
262
                dev->irq_enabled = 0;
 
263
                mutex_unlock(&dev->struct_mutex);
 
264
        }
 
265
 
 
266
        return ret;
 
267
}
 
268
EXPORT_SYMBOL(drm_irq_install);
 
269
 
 
270
/**
 
271
 * Uninstall the IRQ handler.
 
272
 *
 
273
 * \param dev DRM device.
 
274
 *
 
275
 * Calls the driver's \c drm_driver_irq_uninstall() function, and stops the irq.
 
276
 */
 
277
int drm_irq_uninstall(struct drm_device * dev)
 
278
{
 
279
        unsigned long irqflags;
 
280
        int irq_enabled, i;
 
281
 
 
282
        if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
 
283
                return -EINVAL;
 
284
 
 
285
        mutex_lock(&dev->struct_mutex);
 
286
        irq_enabled = dev->irq_enabled;
 
287
        dev->irq_enabled = 0;
 
288
        mutex_unlock(&dev->struct_mutex);
 
289
 
 
290
        /*
 
291
         * Wake up any waiters so they don't hang.
 
292
         */
 
293
        spin_lock_irqsave(&dev->vbl_lock, irqflags);
 
294
        for (i = 0; i < dev->num_crtcs; i++) {
 
295
                DRM_WAKEUP(&dev->vbl_queue[i]);
 
296
                dev->vblank_enabled[i] = 0;
 
297
                dev->last_vblank[i] = dev->driver->get_vblank_counter(dev, i);
 
298
        }
 
299
        spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
 
300
 
 
301
        if (!irq_enabled)
 
302
                return -EINVAL;
 
303
 
 
304
        DRM_DEBUG("irq=%d\n", dev->pdev->irq);
 
305
 
 
306
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
 
307
                vga_client_register(dev->pdev, NULL, NULL, NULL);
 
308
 
 
309
        dev->driver->irq_uninstall(dev);
 
310
 
 
311
        free_irq(dev->pdev->irq, dev);
 
312
 
 
313
        return 0;
 
314
}
 
315
EXPORT_SYMBOL(drm_irq_uninstall);
 
316
 
 
317
/**
 
318
 * IRQ control ioctl.
 
319
 *
 
320
 * \param inode device inode.
 
321
 * \param file_priv DRM file private.
 
322
 * \param cmd command.
 
323
 * \param arg user argument, pointing to a drm_control structure.
 
324
 * \return zero on success or a negative number on failure.
 
325
 *
 
326
 * Calls irq_install() or irq_uninstall() according to \p arg.
 
327
 */
 
328
int drm_control(struct drm_device *dev, void *data,
 
329
                struct drm_file *file_priv)
 
330
{
 
331
        struct drm_control *ctl = data;
 
332
 
 
333
        /* if we haven't irq we fallback for compatibility reasons - this used to be a separate function in drm_dma.h */
 
334
 
 
335
 
 
336
        switch (ctl->func) {
 
337
        case DRM_INST_HANDLER:
 
338
                if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
 
339
                        return 0;
 
340
                if (drm_core_check_feature(dev, DRIVER_MODESET))
 
341
                        return 0;
 
342
                if (dev->if_version < DRM_IF_VERSION(1, 2) &&
 
343
                    ctl->irq != dev->pdev->irq)
 
344
                        return -EINVAL;
 
345
                return drm_irq_install(dev);
 
346
        case DRM_UNINST_HANDLER:
 
347
                if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
 
348
                        return 0;
 
349
                if (drm_core_check_feature(dev, DRIVER_MODESET))
 
350
                        return 0;
 
351
                return drm_irq_uninstall(dev);
 
352
        default:
 
353
                return -EINVAL;
 
354
        }
 
355
}
 
356
 
 
357
/**
 
358
 * drm_vblank_count - retrieve "cooked" vblank counter value
 
359
 * @dev: DRM device
 
360
 * @crtc: which counter to retrieve
 
361
 *
 
362
 * Fetches the "cooked" vblank count value that represents the number of
 
363
 * vblank events since the system was booted, including lost events due to
 
364
 * modesetting activity.
 
365
 */
 
366
u32 drm_vblank_count(struct drm_device *dev, int crtc)
 
367
{
 
368
        return atomic_read(&dev->_vblank_count[crtc]);
 
369
}
 
370
EXPORT_SYMBOL(drm_vblank_count);
 
371
 
 
372
/**
 
373
 * drm_update_vblank_count - update the master vblank counter
 
374
 * @dev: DRM device
 
375
 * @crtc: counter to update
 
376
 *
 
377
 * Call back into the driver to update the appropriate vblank counter
 
378
 * (specified by @crtc).  Deal with wraparound, if it occurred, and
 
379
 * update the last read value so we can deal with wraparound on the next
 
380
 * call if necessary.
 
381
 *
 
382
 * Only necessary when going from off->on, to account for frames we
 
383
 * didn't get an interrupt for.
 
384
 *
 
385
 * Note: caller must hold dev->vbl_lock since this reads & writes
 
386
 * device vblank fields.
 
387
 */
 
388
static void drm_update_vblank_count(struct drm_device *dev, int crtc)
 
389
{
 
390
        u32 cur_vblank, diff;
 
391
 
 
392
        /*
 
393
         * Interrupts were disabled prior to this call, so deal with counter
 
394
         * wrap if needed.
 
395
         * NOTE!  It's possible we lost a full dev->max_vblank_count events
 
396
         * here if the register is small or we had vblank interrupts off for
 
397
         * a long time.
 
398
         */
 
399
        cur_vblank = dev->driver->get_vblank_counter(dev, crtc);
 
400
        diff = cur_vblank - dev->last_vblank[crtc];
 
401
        if (cur_vblank < dev->last_vblank[crtc]) {
 
402
                diff += dev->max_vblank_count;
 
403
 
 
404
                DRM_DEBUG("last_vblank[%d]=0x%x, cur_vblank=0x%x => diff=0x%x\n",
 
405
                          crtc, dev->last_vblank[crtc], cur_vblank, diff);
 
406
        }
 
407
 
 
408
        DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n",
 
409
                  crtc, diff);
 
410
 
 
411
        atomic_add(diff, &dev->_vblank_count[crtc]);
 
412
}
 
413
 
 
414
/**
 
415
 * drm_vblank_get - get a reference count on vblank events
 
416
 * @dev: DRM device
 
417
 * @crtc: which CRTC to own
 
418
 *
 
419
 * Acquire a reference count on vblank events to avoid having them disabled
 
420
 * while in use.
 
421
 *
 
422
 * RETURNS
 
423
 * Zero on success, nonzero on failure.
 
424
 */
 
425
int drm_vblank_get(struct drm_device *dev, int crtc)
 
426
{
 
427
        unsigned long irqflags;
 
428
        int ret = 0;
 
429
 
 
430
        spin_lock_irqsave(&dev->vbl_lock, irqflags);
 
431
        /* Going from 0->1 means we have to enable interrupts again */
 
432
        if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1) {
 
433
                if (!dev->vblank_enabled[crtc]) {
 
434
                        ret = dev->driver->enable_vblank(dev, crtc);
 
435
                        DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", crtc, ret);
 
436
                        if (ret)
 
437
                                atomic_dec(&dev->vblank_refcount[crtc]);
 
438
                        else {
 
439
                                dev->vblank_enabled[crtc] = 1;
 
440
                                drm_update_vblank_count(dev, crtc);
 
441
                        }
 
442
                }
 
443
        } else {
 
444
                if (!dev->vblank_enabled[crtc]) {
 
445
                        atomic_dec(&dev->vblank_refcount[crtc]);
 
446
                        ret = -EINVAL;
 
447
                }
 
448
        }
 
449
        spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
 
450
 
 
451
        return ret;
 
452
}
 
453
EXPORT_SYMBOL(drm_vblank_get);
 
454
 
 
455
/**
 
456
 * drm_vblank_put - give up ownership of vblank events
 
457
 * @dev: DRM device
 
458
 * @crtc: which counter to give up
 
459
 *
 
460
 * Release ownership of a given vblank counter, turning off interrupts
 
461
 * if possible.
 
462
 */
 
463
void drm_vblank_put(struct drm_device *dev, int crtc)
 
464
{
 
465
        BUG_ON (atomic_read (&dev->vblank_refcount[crtc]) == 0);
 
466
 
 
467
        /* Last user schedules interrupt disable */
 
468
        if (atomic_dec_and_test(&dev->vblank_refcount[crtc]))
 
469
                mod_timer(&dev->vblank_disable_timer, jiffies + 5*DRM_HZ);
 
470
}
 
471
EXPORT_SYMBOL(drm_vblank_put);
 
472
 
 
473
void drm_vblank_off(struct drm_device *dev, int crtc)
 
474
{
 
475
        unsigned long irqflags;
 
476
 
 
477
        spin_lock_irqsave(&dev->vbl_lock, irqflags);
 
478
        DRM_WAKEUP(&dev->vbl_queue[crtc]);
 
479
        dev->vblank_enabled[crtc] = 0;
 
480
        dev->last_vblank[crtc] = dev->driver->get_vblank_counter(dev, crtc);
 
481
        spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
 
482
}
 
483
EXPORT_SYMBOL(drm_vblank_off);
 
484
 
 
485
/**
 
486
 * drm_vblank_pre_modeset - account for vblanks across mode sets
 
487
 * @dev: DRM device
 
488
 * @crtc: CRTC in question
 
489
 * @post: post or pre mode set?
 
490
 *
 
491
 * Account for vblank events across mode setting events, which will likely
 
492
 * reset the hardware frame counter.
 
493
 */
 
494
void drm_vblank_pre_modeset(struct drm_device *dev, int crtc)
 
495
{
 
496
        /* vblank is not initialized (IRQ not installed ?) */
 
497
        if (!dev->num_crtcs)
 
498
                return;
 
499
        /*
 
500
         * To avoid all the problems that might happen if interrupts
 
501
         * were enabled/disabled around or between these calls, we just
 
502
         * have the kernel take a reference on the CRTC (just once though
 
503
         * to avoid corrupting the count if multiple, mismatch calls occur),
 
504
         * so that interrupts remain enabled in the interim.
 
505
         */
 
506
        if (!dev->vblank_inmodeset[crtc]) {
 
507
                dev->vblank_inmodeset[crtc] = 0x1;
 
508
                if (drm_vblank_get(dev, crtc) == 0)
 
509
                        dev->vblank_inmodeset[crtc] |= 0x2;
 
510
        }
 
511
}
 
512
EXPORT_SYMBOL(drm_vblank_pre_modeset);
 
513
 
 
514
void drm_vblank_post_modeset(struct drm_device *dev, int crtc)
 
515
{
 
516
        unsigned long irqflags;
 
517
 
 
518
        if (dev->vblank_inmodeset[crtc]) {
 
519
                spin_lock_irqsave(&dev->vbl_lock, irqflags);
 
520
                dev->vblank_disable_allowed = 1;
 
521
                spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
 
522
 
 
523
                if (dev->vblank_inmodeset[crtc] & 0x2)
 
524
                        drm_vblank_put(dev, crtc);
 
525
 
 
526
                dev->vblank_inmodeset[crtc] = 0;
 
527
        }
 
528
}
 
529
EXPORT_SYMBOL(drm_vblank_post_modeset);
 
530
 
 
531
/**
 
532
 * drm_modeset_ctl - handle vblank event counter changes across mode switch
 
533
 * @DRM_IOCTL_ARGS: standard ioctl arguments
 
534
 *
 
535
 * Applications should call the %_DRM_PRE_MODESET and %_DRM_POST_MODESET
 
536
 * ioctls around modesetting so that any lost vblank events are accounted for.
 
537
 *
 
538
 * Generally the counter will reset across mode sets.  If interrupts are
 
539
 * enabled around this call, we don't have to do anything since the counter
 
540
 * will have already been incremented.
 
541
 */
 
542
int drm_modeset_ctl(struct drm_device *dev, void *data,
 
543
                    struct drm_file *file_priv)
 
544
{
 
545
        struct drm_modeset_ctl *modeset = data;
 
546
        int crtc, ret = 0;
 
547
 
 
548
        /* If drm_vblank_init() hasn't been called yet, just no-op */
 
549
        if (!dev->num_crtcs)
 
550
                goto out;
 
551
 
 
552
        crtc = modeset->crtc;
 
553
        if (crtc >= dev->num_crtcs) {
 
554
                ret = -EINVAL;
 
555
                goto out;
 
556
        }
 
557
 
 
558
        switch (modeset->cmd) {
 
559
        case _DRM_PRE_MODESET:
 
560
                drm_vblank_pre_modeset(dev, crtc);
 
561
                break;
 
562
        case _DRM_POST_MODESET:
 
563
                drm_vblank_post_modeset(dev, crtc);
 
564
                break;
 
565
        default:
 
566
                ret = -EINVAL;
 
567
                break;
 
568
        }
 
569
 
 
570
out:
 
571
        return ret;
 
572
}
 
573
 
 
574
static int drm_queue_vblank_event(struct drm_device *dev, int pipe,
 
575
                                  union drm_wait_vblank *vblwait,
 
576
                                  struct drm_file *file_priv)
 
577
{
 
578
        struct drm_pending_vblank_event *e;
 
579
        struct timeval now;
 
580
        unsigned long flags;
 
581
        unsigned int seq;
 
582
 
 
583
        e = kzalloc(sizeof *e, GFP_KERNEL);
 
584
        if (e == NULL)
 
585
                return -ENOMEM;
 
586
 
 
587
        e->pipe = pipe;
 
588
        e->event.base.type = DRM_EVENT_VBLANK;
 
589
        e->event.base.length = sizeof e->event;
 
590
        e->event.user_data = vblwait->request.signal;
 
591
        e->base.event = &e->event.base;
 
592
        e->base.file_priv = file_priv;
 
593
        e->base.destroy = (void (*) (struct drm_pending_event *)) kfree;
 
594
 
 
595
        do_gettimeofday(&now);
 
596
        spin_lock_irqsave(&dev->event_lock, flags);
 
597
 
 
598
        if (file_priv->event_space < sizeof e->event) {
 
599
                spin_unlock_irqrestore(&dev->event_lock, flags);
 
600
                kfree(e);
 
601
                return -ENOMEM;
 
602
        }
 
603
 
 
604
        file_priv->event_space -= sizeof e->event;
 
605
        seq = drm_vblank_count(dev, pipe);
 
606
        if ((vblwait->request.type & _DRM_VBLANK_NEXTONMISS) &&
 
607
            (seq - vblwait->request.sequence) <= (1 << 23)) {
 
608
                vblwait->request.sequence = seq + 1;
 
609
                vblwait->reply.sequence = vblwait->request.sequence;
 
610
        }
 
611
 
 
612
        DRM_DEBUG("event on vblank count %d, current %d, crtc %d\n",
 
613
                  vblwait->request.sequence, seq, pipe);
 
614
 
 
615
        e->event.sequence = vblwait->request.sequence;
 
616
        if ((seq - vblwait->request.sequence) <= (1 << 23)) {
 
617
                e->event.tv_sec = now.tv_sec;
 
618
                e->event.tv_usec = now.tv_usec;
 
619
                drm_vblank_put(dev, e->pipe);
 
620
                list_add_tail(&e->base.link, &e->base.file_priv->event_list);
 
621
                wake_up_interruptible(&e->base.file_priv->event_wait);
 
622
        } else {
 
623
                list_add_tail(&e->base.link, &dev->vblank_event_list);
 
624
        }
 
625
 
 
626
        spin_unlock_irqrestore(&dev->event_lock, flags);
 
627
 
 
628
        return 0;
 
629
}
 
630
 
 
631
/**
 
632
 * Wait for VBLANK.
 
633
 *
 
634
 * \param inode device inode.
 
635
 * \param file_priv DRM file private.
 
636
 * \param cmd command.
 
637
 * \param data user argument, pointing to a drm_wait_vblank structure.
 
638
 * \return zero on success or a negative number on failure.
 
639
 *
 
640
 * This function enables the vblank interrupt on the pipe requested, then
 
641
 * sleeps waiting for the requested sequence number to occur, and drops
 
642
 * the vblank interrupt refcount afterwards. (vblank irq disable follows that
 
643
 * after a timeout with no further vblank waits scheduled).
 
644
 */
 
645
int drm_wait_vblank(struct drm_device *dev, void *data,
 
646
                    struct drm_file *file_priv)
 
647
{
 
648
        union drm_wait_vblank *vblwait = data;
 
649
        int ret = 0;
 
650
        unsigned int flags, seq, crtc;
 
651
 
 
652
        if ((!dev->pdev->irq) || (!dev->irq_enabled))
 
653
                return -EINVAL;
 
654
 
 
655
        if (vblwait->request.type & _DRM_VBLANK_SIGNAL)
 
656
                return -EINVAL;
 
657
 
 
658
        if (vblwait->request.type &
 
659
            ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)) {
 
660
                DRM_ERROR("Unsupported type value 0x%x, supported mask 0x%x\n",
 
661
                          vblwait->request.type,
 
662
                          (_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK));
 
663
                return -EINVAL;
 
664
        }
 
665
 
 
666
        flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK;
 
667
        crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0;
 
668
 
 
669
        if (crtc >= dev->num_crtcs)
 
670
                return -EINVAL;
 
671
 
 
672
        ret = drm_vblank_get(dev, crtc);
 
673
        if (ret) {
 
674
                DRM_DEBUG("failed to acquire vblank counter, %d\n", ret);
 
675
                return ret;
 
676
        }
 
677
        seq = drm_vblank_count(dev, crtc);
 
678
 
 
679
        switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) {
 
680
        case _DRM_VBLANK_RELATIVE:
 
681
                vblwait->request.sequence += seq;
 
682
                vblwait->request.type &= ~_DRM_VBLANK_RELATIVE;
 
683
        case _DRM_VBLANK_ABSOLUTE:
 
684
                break;
 
685
        default:
 
686
                ret = -EINVAL;
 
687
                goto done;
 
688
        }
 
689
 
 
690
        if (flags & _DRM_VBLANK_EVENT)
 
691
                return drm_queue_vblank_event(dev, crtc, vblwait, file_priv);
 
692
 
 
693
        if ((flags & _DRM_VBLANK_NEXTONMISS) &&
 
694
            (seq - vblwait->request.sequence) <= (1<<23)) {
 
695
                vblwait->request.sequence = seq + 1;
 
696
        }
 
697
 
 
698
        DRM_DEBUG("waiting on vblank count %d, crtc %d\n",
 
699
                  vblwait->request.sequence, crtc);
 
700
        dev->last_vblank_wait[crtc] = vblwait->request.sequence;
 
701
        DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ,
 
702
                    (((drm_vblank_count(dev, crtc) -
 
703
                       vblwait->request.sequence) <= (1 << 23)) ||
 
704
                     !dev->irq_enabled));
 
705
 
 
706
        if (ret != -EINTR) {
 
707
                struct timeval now;
 
708
 
 
709
                do_gettimeofday(&now);
 
710
 
 
711
                vblwait->reply.tval_sec = now.tv_sec;
 
712
                vblwait->reply.tval_usec = now.tv_usec;
 
713
                vblwait->reply.sequence = drm_vblank_count(dev, crtc);
 
714
                DRM_DEBUG("returning %d to client\n",
 
715
                          vblwait->reply.sequence);
 
716
        } else {
 
717
                DRM_DEBUG("vblank wait interrupted by signal\n");
 
718
        }
 
719
 
 
720
done:
 
721
        drm_vblank_put(dev, crtc);
 
722
        return ret;
 
723
}
 
724
 
 
725
void drm_handle_vblank_events(struct drm_device *dev, int crtc)
 
726
{
 
727
        struct drm_pending_vblank_event *e, *t;
 
728
        struct timeval now;
 
729
        unsigned long flags;
 
730
        unsigned int seq;
 
731
 
 
732
        do_gettimeofday(&now);
 
733
        seq = drm_vblank_count(dev, crtc);
 
734
 
 
735
        spin_lock_irqsave(&dev->event_lock, flags);
 
736
 
 
737
        list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) {
 
738
                if (e->pipe != crtc)
 
739
                        continue;
 
740
                if ((seq - e->event.sequence) > (1<<23))
 
741
                        continue;
 
742
 
 
743
                DRM_DEBUG("vblank event on %d, current %d\n",
 
744
                          e->event.sequence, seq);
 
745
 
 
746
                e->event.sequence = seq;
 
747
                e->event.tv_sec = now.tv_sec;
 
748
                e->event.tv_usec = now.tv_usec;
 
749
                drm_vblank_put(dev, e->pipe);
 
750
                list_move_tail(&e->base.link, &e->base.file_priv->event_list);
 
751
                wake_up_interruptible(&e->base.file_priv->event_wait);
 
752
        }
 
753
 
 
754
        spin_unlock_irqrestore(&dev->event_lock, flags);
 
755
}
 
756
 
 
757
/**
 
758
 * drm_handle_vblank - handle a vblank event
 
759
 * @dev: DRM device
 
760
 * @crtc: where this event occurred
 
761
 *
 
762
 * Drivers should call this routine in their vblank interrupt handlers to
 
763
 * update the vblank counter and send any signals that may be pending.
 
764
 */
 
765
void drm_handle_vblank(struct drm_device *dev, int crtc)
 
766
{
 
767
        if (!dev->num_crtcs)
 
768
                return;
 
769
 
 
770
        atomic_inc(&dev->_vblank_count[crtc]);
 
771
        DRM_WAKEUP(&dev->vbl_queue[crtc]);
 
772
        drm_handle_vblank_events(dev, crtc);
 
773
}
 
774
EXPORT_SYMBOL(drm_handle_vblank);