diff options
| -rw-r--r-- | drivers/gpu/drm/drm_drv.c | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/drm_irq.c | 447 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/i915_dma.c | 5 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/i915_drv.c | 11 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 20 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/i915_irq.c | 395 | ||||
| -rw-r--r-- | drivers/gpu/drm/mga/mga_drv.c | 29 | ||||
| -rw-r--r-- | drivers/gpu/drm/mga/mga_drv.h | 6 | ||||
| -rw-r--r-- | drivers/gpu/drm/mga/mga_irq.c | 74 | ||||
| -rw-r--r-- | drivers/gpu/drm/r128/r128_drv.c | 29 | ||||
| -rw-r--r-- | drivers/gpu/drm/r128/r128_drv.h | 11 | ||||
| -rw-r--r-- | drivers/gpu/drm/r128/r128_irq.c | 55 | ||||
| -rw-r--r-- | drivers/gpu/drm/radeon/radeon_cp.c | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/radeon/radeon_drv.c | 32 | ||||
| -rw-r--r-- | drivers/gpu/drm/radeon/radeon_drv.h | 27 | ||||
| -rw-r--r-- | drivers/gpu/drm/radeon/radeon_irq.c | 268 | ||||
| -rw-r--r-- | drivers/gpu/drm/via/via_drv.c | 26 | ||||
| -rw-r--r-- | drivers/gpu/drm/via/via_drv.h | 16 | ||||
| -rw-r--r-- | drivers/gpu/drm/via/via_irq.c | 102 | ||||
| -rw-r--r-- | include/drm/drm.h | 15 | ||||
| -rw-r--r-- | include/drm/drmP.h | 90 |
21 files changed, 1189 insertions, 473 deletions
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 452c2d866ec5..fb45fe7aeb8c 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c | |||
| @@ -116,6 +116,8 @@ static struct drm_ioctl_desc drm_ioctls[] = { | |||
| 116 | 116 | ||
| 117 | DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank, 0), | 117 | DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank, 0), |
| 118 | 118 | ||
| 119 | DRM_IOCTL_DEF(DRM_IOCTL_MODESET_CTL, drm_modeset_ctl, 0), | ||
| 120 | |||
| 119 | DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | 121 | DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
| 120 | }; | 122 | }; |
| 121 | 123 | ||
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 61ed5158f783..d0c13d954f52 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c | |||
| @@ -71,19 +71,131 @@ int drm_irq_by_busid(struct drm_device *dev, void *data, | |||
| 71 | return 0; | 71 | return 0; |
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | static void vblank_disable_fn(unsigned long arg) | ||
| 75 | { | ||
| 76 | struct drm_device *dev = (struct drm_device *)arg; | ||
| 77 | unsigned long irqflags; | ||
| 78 | int i; | ||
| 79 | |||
| 80 | if (!dev->vblank_disable_allowed) | ||
| 81 | return; | ||
| 82 | |||
| 83 | for (i = 0; i < dev->num_crtcs; i++) { | ||
| 84 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | ||
| 85 | if (atomic_read(&dev->vblank_refcount[i]) == 0 && | ||
| 86 | dev->vblank_enabled[i]) { | ||
| 87 | DRM_DEBUG("disabling vblank on crtc %d\n", i); | ||
| 88 | dev->last_vblank[i] = | ||
| 89 | dev->driver->get_vblank_counter(dev, i); | ||
| 90 | dev->driver->disable_vblank(dev, i); | ||
| 91 | dev->vblank_enabled[i] = 0; | ||
| 92 | } | ||
| 93 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | ||
| 94 | } | ||
| 95 | } | ||
| 96 | |||
| 97 | static void drm_vblank_cleanup(struct drm_device *dev) | ||
| 98 | { | ||
| 99 | /* Bail if the driver didn't call drm_vblank_init() */ | ||
| 100 | if (dev->num_crtcs == 0) | ||
| 101 | return; | ||
| 102 | |||
| 103 | del_timer(&dev->vblank_disable_timer); | ||
| 104 | |||
| 105 | vblank_disable_fn((unsigned long)dev); | ||
| 106 | |||
| 107 | drm_free(dev->vbl_queue, sizeof(*dev->vbl_queue) * dev->num_crtcs, | ||
| 108 | DRM_MEM_DRIVER); | ||
| 109 | drm_free(dev->vbl_sigs, sizeof(*dev->vbl_sigs) * dev->num_crtcs, | ||
| 110 | DRM_MEM_DRIVER); | ||
| 111 | drm_free(dev->_vblank_count, sizeof(*dev->_vblank_count) * | ||
| 112 | dev->num_crtcs, DRM_MEM_DRIVER); | ||
| 113 | drm_free(dev->vblank_refcount, sizeof(*dev->vblank_refcount) * | ||
| 114 | dev->num_crtcs, DRM_MEM_DRIVER); | ||
| 115 | drm_free(dev->vblank_enabled, sizeof(*dev->vblank_enabled) * | ||
| 116 | dev->num_crtcs, DRM_MEM_DRIVER); | ||
| 117 | drm_free(dev->last_vblank, sizeof(*dev->last_vblank) * dev->num_crtcs, | ||
| 118 | DRM_MEM_DRIVER); | ||
| 119 | drm_free(dev->vblank_inmodeset, sizeof(*dev->vblank_inmodeset) * | ||
| 120 | dev->num_crtcs, DRM_MEM_DRIVER); | ||
| 121 | |||
| 122 | dev->num_crtcs = 0; | ||
| 123 | } | ||
| 124 | |||
| 125 | int drm_vblank_init(struct drm_device *dev, int num_crtcs) | ||
| 126 | { | ||
| 127 | int i, ret = -ENOMEM; | ||
| 128 | |||
| 129 | setup_timer(&dev->vblank_disable_timer, vblank_disable_fn, | ||
| 130 | (unsigned long)dev); | ||
| 131 | spin_lock_init(&dev->vbl_lock); | ||
| 132 | atomic_set(&dev->vbl_signal_pending, 0); | ||
| 133 | dev->num_crtcs = num_crtcs; | ||
| 134 | |||
| 135 | dev->vbl_queue = drm_alloc(sizeof(wait_queue_head_t) * num_crtcs, | ||
| 136 | DRM_MEM_DRIVER); | ||
| 137 | if (!dev->vbl_queue) | ||
| 138 | goto err; | ||
| 139 | |||
| 140 | dev->vbl_sigs = drm_alloc(sizeof(struct list_head) * num_crtcs, | ||
| 141 | DRM_MEM_DRIVER); | ||
| 142 | if (!dev->vbl_sigs) | ||
| 143 | goto err; | ||
| 144 | |||
| 145 | dev->_vblank_count = drm_alloc(sizeof(atomic_t) * num_crtcs, | ||
| 146 | DRM_MEM_DRIVER); | ||
| 147 | if (!dev->_vblank_count) | ||
| 148 | goto err; | ||
| 149 | |||
| 150 | dev->vblank_refcount = drm_alloc(sizeof(atomic_t) * num_crtcs, | ||
| 151 | DRM_MEM_DRIVER); | ||
| 152 | if (!dev->vblank_refcount) | ||
| 153 | goto err; | ||
| 154 | |||
| 155 | dev->vblank_enabled = drm_calloc(num_crtcs, sizeof(int), | ||
| 156 | DRM_MEM_DRIVER); | ||
| 157 | if (!dev->vblank_enabled) | ||
| 158 | goto err; | ||
| 159 | |||
| 160 | dev->last_vblank = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER); | ||
| 161 | if (!dev->last_vblank) | ||
| 162 | goto err; | ||
| 163 | |||
| 164 | dev->vblank_inmodeset = drm_calloc(num_crtcs, sizeof(int), | ||
| 165 | DRM_MEM_DRIVER); | ||
| 166 | if (!dev->vblank_inmodeset) | ||
| 167 | goto err; | ||
| 168 | |||
| 169 | /* Zero per-crtc vblank stuff */ | ||
| 170 | for (i = 0; i < num_crtcs; i++) { | ||
| 171 | init_waitqueue_head(&dev->vbl_queue[i]); | ||
| 172 | INIT_LIST_HEAD(&dev->vbl_sigs[i]); | ||
| 173 | atomic_set(&dev->_vblank_count[i], 0); | ||
| 174 | atomic_set(&dev->vblank_refcount[i], 0); | ||
| 175 | } | ||
| 176 | |||
| 177 | dev->vblank_disable_allowed = 0; | ||
| 178 | |||
| 179 | return 0; | ||
| 180 | |||
| 181 | err: | ||
| 182 | drm_vblank_cleanup(dev); | ||
| 183 | return ret; | ||
| 184 | } | ||
| 185 | EXPORT_SYMBOL(drm_vblank_init); | ||
| 186 | |||
| 74 | /** | 187 | /** |
| 75 | * Install IRQ handler. | 188 | * Install IRQ handler. |
| 76 | * | 189 | * |
| 77 | * \param dev DRM device. | 190 | * \param dev DRM device. |
| 78 | * \param irq IRQ number. | ||
| 79 | * | 191 | * |
| 80 | * Initializes the IRQ related data, and setups drm_device::vbl_queue. Installs the handler, calling the driver | 192 | * Initializes the IRQ related data. Installs the handler, calling the driver |
| 81 | * \c drm_driver_irq_preinstall() and \c drm_driver_irq_postinstall() functions | 193 | * \c drm_driver_irq_preinstall() and \c drm_driver_irq_postinstall() functions |
| 82 | * before and after the installation. | 194 | * before and after the installation. |
| 83 | */ | 195 | */ |
| 84 | static int drm_irq_install(struct drm_device * dev) | 196 | int drm_irq_install(struct drm_device *dev) |
| 85 | { | 197 | { |
| 86 | int ret; | 198 | int ret = 0; |
| 87 | unsigned long sh_flags = 0; | 199 | unsigned long sh_flags = 0; |
| 88 | 200 | ||
| 89 | if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) | 201 | if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) |
| @@ -109,17 +221,6 @@ static int drm_irq_install(struct drm_device * dev) | |||
| 109 | 221 | ||
| 110 | DRM_DEBUG("irq=%d\n", dev->pdev->irq); | 222 | DRM_DEBUG("irq=%d\n", dev->pdev->irq); |
| 111 | 223 | ||
| 112 | if (drm_core_check_feature(dev, DRIVER_IRQ_VBL)) { | ||
| 113 | init_waitqueue_head(&dev->vbl_queue); | ||
| 114 | |||
| 115 | spin_lock_init(&dev->vbl_lock); | ||
| 116 | |||
| 117 | INIT_LIST_HEAD(&dev->vbl_sigs); | ||
| 118 | INIT_LIST_HEAD(&dev->vbl_sigs2); | ||
| 119 | |||
| 120 | dev->vbl_pending = 0; | ||
| 121 | } | ||
| 122 | |||
| 123 | /* Before installing handler */ | 224 | /* Before installing handler */ |
| 124 | dev->driver->irq_preinstall(dev); | 225 | dev->driver->irq_preinstall(dev); |
| 125 | 226 | ||
| @@ -141,10 +242,16 @@ static int drm_irq_install(struct drm_device * dev) | |||
| 141 | } | 242 | } |
| 142 | 243 | ||
| 143 | /* After installing handler */ | 244 | /* After installing handler */ |
| 144 | dev->driver->irq_postinstall(dev); | 245 | ret = dev->driver->irq_postinstall(dev); |
| 246 | if (ret < 0) { | ||
| 247 | mutex_lock(&dev->struct_mutex); | ||
| 248 | dev->irq_enabled = 0; | ||
| 249 | mutex_unlock(&dev->struct_mutex); | ||
| 250 | } | ||
| 145 | 251 | ||
| 146 | return 0; | 252 | return ret; |
| 147 | } | 253 | } |
| 254 | EXPORT_SYMBOL(drm_irq_install); | ||
| 148 | 255 | ||
| 149 | /** | 256 | /** |
| 150 | * Uninstall the IRQ handler. | 257 | * Uninstall the IRQ handler. |
| @@ -174,11 +281,12 @@ int drm_irq_uninstall(struct drm_device * dev) | |||
| 174 | 281 | ||
| 175 | free_irq(dev->pdev->irq, dev); | 282 | free_irq(dev->pdev->irq, dev); |
| 176 | 283 | ||
| 284 | drm_vblank_cleanup(dev); | ||
| 285 | |||
| 177 | dev->locked_tasklet_func = NULL; | 286 | dev->locked_tasklet_func = NULL; |
| 178 | 287 | ||
| 179 | return 0; | 288 | return 0; |
| 180 | } | 289 | } |
| 181 | |||
| 182 | EXPORT_SYMBOL(drm_irq_uninstall); | 290 | EXPORT_SYMBOL(drm_irq_uninstall); |
| 183 | 291 | ||
| 184 | /** | 292 | /** |
| @@ -218,6 +326,174 @@ int drm_control(struct drm_device *dev, void *data, | |||
| 218 | } | 326 | } |
| 219 | 327 | ||
| 220 | /** | 328 | /** |
| 329 | * drm_vblank_count - retrieve "cooked" vblank counter value | ||
| 330 | * @dev: DRM device | ||
| 331 | * @crtc: which counter to retrieve | ||
| 332 | * | ||
| 333 | * Fetches the "cooked" vblank count value that represents the number of | ||
| 334 | * vblank events since the system was booted, including lost events due to | ||
| 335 | * modesetting activity. | ||
| 336 | */ | ||
| 337 | u32 drm_vblank_count(struct drm_device *dev, int crtc) | ||
| 338 | { | ||
| 339 | return atomic_read(&dev->_vblank_count[crtc]); | ||
| 340 | } | ||
| 341 | EXPORT_SYMBOL(drm_vblank_count); | ||
| 342 | |||
| 343 | /** | ||
| 344 | * drm_update_vblank_count - update the master vblank counter | ||
| 345 | * @dev: DRM device | ||
| 346 | * @crtc: counter to update | ||
| 347 | * | ||
| 348 | * Call back into the driver to update the appropriate vblank counter | ||
| 349 | * (specified by @crtc). Deal with wraparound, if it occurred, and | ||
| 350 | * update the last read value so we can deal with wraparound on the next | ||
| 351 | * call if necessary. | ||
| 352 | * | ||
| 353 | * Only necessary when going from off->on, to account for frames we | ||
| 354 | * didn't get an interrupt for. | ||
| 355 | * | ||
| 356 | * Note: caller must hold dev->vbl_lock since this reads & writes | ||
| 357 | * device vblank fields. | ||
| 358 | */ | ||
| 359 | static void drm_update_vblank_count(struct drm_device *dev, int crtc) | ||
| 360 | { | ||
| 361 | u32 cur_vblank, diff; | ||
| 362 | |||
| 363 | /* | ||
| 364 | * Interrupts were disabled prior to this call, so deal with counter | ||
| 365 | * wrap if needed. | ||
| 366 | * NOTE! It's possible we lost a full dev->max_vblank_count events | ||
| 367 | * here if the register is small or we had vblank interrupts off for | ||
| 368 | * a long time. | ||
| 369 | */ | ||
| 370 | cur_vblank = dev->driver->get_vblank_counter(dev, crtc); | ||
| 371 | diff = cur_vblank - dev->last_vblank[crtc]; | ||
| 372 | if (cur_vblank < dev->last_vblank[crtc]) { | ||
| 373 | diff += dev->max_vblank_count; | ||
| 374 | |||
| 375 | DRM_DEBUG("last_vblank[%d]=0x%x, cur_vblank=0x%x => diff=0x%x\n", | ||
| 376 | crtc, dev->last_vblank[crtc], cur_vblank, diff); | ||
| 377 | } | ||
| 378 | |||
| 379 | DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n", | ||
| 380 | crtc, diff); | ||
| 381 | |||
| 382 | atomic_add(diff, &dev->_vblank_count[crtc]); | ||
| 383 | } | ||
| 384 | |||
| 385 | /** | ||
| 386 | * drm_vblank_get - get a reference count on vblank events | ||
| 387 | * @dev: DRM device | ||
| 388 | * @crtc: which CRTC to own | ||
| 389 | * | ||
| 390 | * Acquire a reference count on vblank events to avoid having them disabled | ||
| 391 | * while in use. | ||
| 392 | * | ||
| 393 | * RETURNS | ||
| 394 | * Zero on success, nonzero on failure. | ||
| 395 | */ | ||
| 396 | int drm_vblank_get(struct drm_device *dev, int crtc) | ||
| 397 | { | ||
| 398 | unsigned long irqflags; | ||
| 399 | int ret = 0; | ||
| 400 | |||
| 401 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | ||
| 402 | /* Going from 0->1 means we have to enable interrupts again */ | ||
| 403 | if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1 && | ||
| 404 | !dev->vblank_enabled[crtc]) { | ||
| 405 | ret = dev->driver->enable_vblank(dev, crtc); | ||
| 406 | DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", crtc, ret); | ||
| 407 | if (ret) | ||
| 408 | atomic_dec(&dev->vblank_refcount[crtc]); | ||
| 409 | else { | ||
| 410 | dev->vblank_enabled[crtc] = 1; | ||
| 411 | drm_update_vblank_count(dev, crtc); | ||
| 412 | } | ||
| 413 | } | ||
| 414 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | ||
| 415 | |||
| 416 | return ret; | ||
| 417 | } | ||
| 418 | EXPORT_SYMBOL(drm_vblank_get); | ||
| 419 | |||
| 420 | /** | ||
| 421 | * drm_vblank_put - give up ownership of vblank events | ||
| 422 | * @dev: DRM device | ||
| 423 | * @crtc: which counter to give up | ||
| 424 | * | ||
| 425 | * Release ownership of a given vblank counter, turning off interrupts | ||
| 426 | * if possible. | ||
| 427 | */ | ||
| 428 | void drm_vblank_put(struct drm_device *dev, int crtc) | ||
| 429 | { | ||
| 430 | /* Last user schedules interrupt disable */ | ||
| 431 | if (atomic_dec_and_test(&dev->vblank_refcount[crtc])) | ||
| 432 | mod_timer(&dev->vblank_disable_timer, jiffies + 5*DRM_HZ); | ||
| 433 | } | ||
| 434 | EXPORT_SYMBOL(drm_vblank_put); | ||
| 435 | |||
| 436 | /** | ||
| 437 | * drm_modeset_ctl - handle vblank event counter changes across mode switch | ||
| 438 | * @DRM_IOCTL_ARGS: standard ioctl arguments | ||
| 439 | * | ||
| 440 | * Applications should call the %_DRM_PRE_MODESET and %_DRM_POST_MODESET | ||
| 441 | * ioctls around modesetting so that any lost vblank events are accounted for. | ||
| 442 | * | ||
| 443 | * Generally the counter will reset across mode sets. If interrupts are | ||
| 444 | * enabled around this call, we don't have to do anything since the counter | ||
| 445 | * will have already been incremented. | ||
| 446 | */ | ||
| 447 | int drm_modeset_ctl(struct drm_device *dev, void *data, | ||
| 448 | struct drm_file *file_priv) | ||
| 449 | { | ||
| 450 | struct drm_modeset_ctl *modeset = data; | ||
| 451 | unsigned long irqflags; | ||
| 452 | int crtc, ret = 0; | ||
| 453 | |||
| 454 | /* If drm_vblank_init() hasn't been called yet, just no-op */ | ||
| 455 | if (!dev->num_crtcs) | ||
| 456 | goto out; | ||
| 457 | |||
| 458 | crtc = modeset->crtc; | ||
| 459 | if (crtc >= dev->num_crtcs) { | ||
| 460 | ret = -EINVAL; | ||
| 461 | goto out; | ||
| 462 | } | ||
| 463 | |||
| 464 | /* | ||
| 465 | * To avoid all the problems that might happen if interrupts | ||
| 466 | * were enabled/disabled around or between these calls, we just | ||
| 467 | * have the kernel take a reference on the CRTC (just once though | ||
| 468 | * to avoid corrupting the count if multiple, mismatch calls occur), | ||
| 469 | * so that interrupts remain enabled in the interim. | ||
| 470 | */ | ||
| 471 | switch (modeset->cmd) { | ||
| 472 | case _DRM_PRE_MODESET: | ||
| 473 | if (!dev->vblank_inmodeset[crtc]) { | ||
| 474 | dev->vblank_inmodeset[crtc] = 1; | ||
| 475 | drm_vblank_get(dev, crtc); | ||
| 476 | } | ||
| 477 | break; | ||
| 478 | case _DRM_POST_MODESET: | ||
| 479 | if (dev->vblank_inmodeset[crtc]) { | ||
| 480 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | ||
| 481 | dev->vblank_disable_allowed = 1; | ||
| 482 | dev->vblank_inmodeset[crtc] = 0; | ||
| 483 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | ||
| 484 | drm_vblank_put(dev, crtc); | ||
| 485 | } | ||
| 486 | break; | ||
| 487 | default: | ||
| 488 | ret = -EINVAL; | ||
| 489 | break; | ||
| 490 | } | ||
| 491 | |||
| 492 | out: | ||
| 493 | return ret; | ||
| 494 | } | ||
| 495 | |||
| 496 | /** | ||
| 221 | * Wait for VBLANK. | 497 | * Wait for VBLANK. |
| 222 | * | 498 | * |
| 223 | * \param inode device inode. | 499 | * \param inode device inode. |
| @@ -236,12 +512,12 @@ int drm_control(struct drm_device *dev, void *data, | |||
| 236 | * | 512 | * |
| 237 | * If a signal is not requested, then calls vblank_wait(). | 513 | * If a signal is not requested, then calls vblank_wait(). |
| 238 | */ | 514 | */ |
| 239 | int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv) | 515 | int drm_wait_vblank(struct drm_device *dev, void *data, |
| 516 | struct drm_file *file_priv) | ||
| 240 | { | 517 | { |
| 241 | union drm_wait_vblank *vblwait = data; | 518 | union drm_wait_vblank *vblwait = data; |
| 242 | struct timeval now; | ||
| 243 | int ret = 0; | 519 | int ret = 0; |
| 244 | unsigned int flags, seq; | 520 | unsigned int flags, seq, crtc; |
| 245 | 521 | ||
| 246 | if ((!dev->pdev->irq) || (!dev->irq_enabled)) | 522 | if ((!dev->pdev->irq) || (!dev->irq_enabled)) |
| 247 | return -EINVAL; | 523 | return -EINVAL; |
| @@ -255,13 +531,17 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr | |||
| 255 | } | 531 | } |
| 256 | 532 | ||
| 257 | flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK; | 533 | flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK; |
| 534 | crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0; | ||
| 258 | 535 | ||
| 259 | if (!drm_core_check_feature(dev, (flags & _DRM_VBLANK_SECONDARY) ? | 536 | if (crtc >= dev->num_crtcs) |
| 260 | DRIVER_IRQ_VBL2 : DRIVER_IRQ_VBL)) | ||
| 261 | return -EINVAL; | 537 | return -EINVAL; |
| 262 | 538 | ||
| 263 | seq = atomic_read((flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2 | 539 | ret = drm_vblank_get(dev, crtc); |
| 264 | : &dev->vbl_received); | 540 | if (ret) { |
| 541 | DRM_ERROR("failed to acquire vblank counter, %d\n", ret); | ||
| 542 | return ret; | ||
| 543 | } | ||
| 544 | seq = drm_vblank_count(dev, crtc); | ||
| 265 | 545 | ||
| 266 | switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) { | 546 | switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) { |
| 267 | case _DRM_VBLANK_RELATIVE: | 547 | case _DRM_VBLANK_RELATIVE: |
| @@ -270,7 +550,8 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr | |||
| 270 | case _DRM_VBLANK_ABSOLUTE: | 550 | case _DRM_VBLANK_ABSOLUTE: |
| 271 | break; | 551 | break; |
| 272 | default: | 552 | default: |
| 273 | return -EINVAL; | 553 | ret = -EINVAL; |
| 554 | goto done; | ||
| 274 | } | 555 | } |
| 275 | 556 | ||
| 276 | if ((flags & _DRM_VBLANK_NEXTONMISS) && | 557 | if ((flags & _DRM_VBLANK_NEXTONMISS) && |
| @@ -280,8 +561,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr | |||
| 280 | 561 | ||
| 281 | if (flags & _DRM_VBLANK_SIGNAL) { | 562 | if (flags & _DRM_VBLANK_SIGNAL) { |
| 282 | unsigned long irqflags; | 563 | unsigned long irqflags; |
| 283 | struct list_head *vbl_sigs = (flags & _DRM_VBLANK_SECONDARY) | 564 | struct list_head *vbl_sigs = &dev->vbl_sigs[crtc]; |
| 284 | ? &dev->vbl_sigs2 : &dev->vbl_sigs; | ||
| 285 | struct drm_vbl_sig *vbl_sig; | 565 | struct drm_vbl_sig *vbl_sig; |
| 286 | 566 | ||
| 287 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | 567 | spin_lock_irqsave(&dev->vbl_lock, irqflags); |
| @@ -302,22 +582,29 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr | |||
| 302 | } | 582 | } |
| 303 | } | 583 | } |
| 304 | 584 | ||
| 305 | if (dev->vbl_pending >= 100) { | 585 | if (atomic_read(&dev->vbl_signal_pending) >= 100) { |
| 306 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | 586 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); |
| 307 | return -EBUSY; | 587 | ret = -EBUSY; |
| 588 | goto done; | ||
| 308 | } | 589 | } |
| 309 | 590 | ||
| 310 | dev->vbl_pending++; | ||
| 311 | |||
| 312 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | 591 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); |
| 313 | 592 | ||
| 314 | if (! | 593 | vbl_sig = drm_calloc(1, sizeof(struct drm_vbl_sig), |
| 315 | (vbl_sig = | 594 | DRM_MEM_DRIVER); |
| 316 | drm_alloc(sizeof(struct drm_vbl_sig), DRM_MEM_DRIVER))) { | 595 | if (!vbl_sig) { |
| 317 | return -ENOMEM; | 596 | ret = -ENOMEM; |
| 597 | goto done; | ||
| 598 | } | ||
| 599 | |||
| 600 | ret = drm_vblank_get(dev, crtc); | ||
| 601 | if (ret) { | ||
| 602 | drm_free(vbl_sig, sizeof(struct drm_vbl_sig), | ||
| 603 | DRM_MEM_DRIVER); | ||
| 604 | return ret; | ||
| 318 | } | 605 | } |
| 319 | 606 | ||
| 320 | memset((void *)vbl_sig, 0, sizeof(*vbl_sig)); | 607 | atomic_inc(&dev->vbl_signal_pending); |
| 321 | 608 | ||
| 322 | vbl_sig->sequence = vblwait->request.sequence; | 609 | vbl_sig->sequence = vblwait->request.sequence; |
| 323 | vbl_sig->info.si_signo = vblwait->request.signal; | 610 | vbl_sig->info.si_signo = vblwait->request.signal; |
| @@ -331,20 +618,29 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr | |||
| 331 | 618 | ||
| 332 | vblwait->reply.sequence = seq; | 619 | vblwait->reply.sequence = seq; |
| 333 | } else { | 620 | } else { |
| 334 | if (flags & _DRM_VBLANK_SECONDARY) { | 621 | DRM_DEBUG("waiting on vblank count %d, crtc %d\n", |
| 335 | if (dev->driver->vblank_wait2) | 622 | vblwait->request.sequence, crtc); |
| 336 | ret = dev->driver->vblank_wait2(dev, &vblwait->request.sequence); | 623 | DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ, |
| 337 | } else if (dev->driver->vblank_wait) | 624 | ((drm_vblank_count(dev, crtc) |
| 338 | ret = | 625 | - vblwait->request.sequence) <= (1 << 23))); |
| 339 | dev->driver->vblank_wait(dev, | 626 | |
| 340 | &vblwait->request.sequence); | 627 | if (ret != -EINTR) { |
| 341 | 628 | struct timeval now; | |
| 342 | do_gettimeofday(&now); | 629 | |
| 343 | vblwait->reply.tval_sec = now.tv_sec; | 630 | do_gettimeofday(&now); |
| 344 | vblwait->reply.tval_usec = now.tv_usec; | 631 | |
| 632 | vblwait->reply.tval_sec = now.tv_sec; | ||
| 633 | vblwait->reply.tval_usec = now.tv_usec; | ||
| 634 | vblwait->reply.sequence = drm_vblank_count(dev, crtc); | ||
| 635 | DRM_DEBUG("returning %d to client\n", | ||
| 636 | vblwait->reply.sequence); | ||
| 637 | } else { | ||
| 638 | DRM_DEBUG("vblank wait interrupted by signal\n"); | ||
| 639 | } | ||
| 345 | } | 640 | } |
| 346 | 641 | ||
| 347 | done: | 642 | done: |
| 643 | drm_vblank_put(dev, crtc); | ||
| 348 | return ret; | 644 | return ret; |
| 349 | } | 645 | } |
| 350 | 646 | ||
| @@ -352,44 +648,57 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr | |||
| 352 | * Send the VBLANK signals. | 648 | * Send the VBLANK signals. |
| 353 | * | 649 | * |
| 354 | * \param dev DRM device. | 650 | * \param dev DRM device. |
| 651 | * \param crtc CRTC where the vblank event occurred | ||
| 355 | * | 652 | * |
| 356 | * Sends a signal for each task in drm_device::vbl_sigs and empties the list. | 653 | * Sends a signal for each task in drm_device::vbl_sigs and empties the list. |
| 357 | * | 654 | * |
| 358 | * If a signal is not requested, then calls vblank_wait(). | 655 | * If a signal is not requested, then calls vblank_wait(). |
| 359 | */ | 656 | */ |
| 360 | void drm_vbl_send_signals(struct drm_device * dev) | 657 | static void drm_vbl_send_signals(struct drm_device *dev, int crtc) |
| 361 | { | 658 | { |
| 659 | struct drm_vbl_sig *vbl_sig, *tmp; | ||
| 660 | struct list_head *vbl_sigs; | ||
| 661 | unsigned int vbl_seq; | ||
| 362 | unsigned long flags; | 662 | unsigned long flags; |
| 363 | int i; | ||
| 364 | 663 | ||
| 365 | spin_lock_irqsave(&dev->vbl_lock, flags); | 664 | spin_lock_irqsave(&dev->vbl_lock, flags); |
| 366 | 665 | ||
| 367 | for (i = 0; i < 2; i++) { | 666 | vbl_sigs = &dev->vbl_sigs[crtc]; |
| 368 | struct drm_vbl_sig *vbl_sig, *tmp; | 667 | vbl_seq = drm_vblank_count(dev, crtc); |
| 369 | struct list_head *vbl_sigs = i ? &dev->vbl_sigs2 : &dev->vbl_sigs; | ||
| 370 | unsigned int vbl_seq = atomic_read(i ? &dev->vbl_received2 : | ||
| 371 | &dev->vbl_received); | ||
| 372 | 668 | ||
| 373 | list_for_each_entry_safe(vbl_sig, tmp, vbl_sigs, head) { | 669 | list_for_each_entry_safe(vbl_sig, tmp, vbl_sigs, head) { |
| 374 | if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) { | 670 | if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) { |
| 375 | vbl_sig->info.si_code = vbl_seq; | 671 | vbl_sig->info.si_code = vbl_seq; |
| 376 | send_sig_info(vbl_sig->info.si_signo, | 672 | send_sig_info(vbl_sig->info.si_signo, |
| 377 | &vbl_sig->info, vbl_sig->task); | 673 | &vbl_sig->info, vbl_sig->task); |
| 378 | 674 | ||
| 379 | list_del(&vbl_sig->head); | 675 | list_del(&vbl_sig->head); |
| 380 | |||
| 381 | drm_free(vbl_sig, sizeof(*vbl_sig), | ||
| 382 | DRM_MEM_DRIVER); | ||
| 383 | 676 | ||
| 384 | dev->vbl_pending--; | 677 | drm_free(vbl_sig, sizeof(*vbl_sig), |
| 385 | } | 678 | DRM_MEM_DRIVER); |
| 386 | } | 679 | atomic_dec(&dev->vbl_signal_pending); |
| 680 | drm_vblank_put(dev, crtc); | ||
| 681 | } | ||
| 387 | } | 682 | } |
| 388 | 683 | ||
| 389 | spin_unlock_irqrestore(&dev->vbl_lock, flags); | 684 | spin_unlock_irqrestore(&dev->vbl_lock, flags); |
| 390 | } | 685 | } |
| 391 | 686 | ||
| 392 | EXPORT_SYMBOL(drm_vbl_send_signals); | 687 | /** |
| 688 | * drm_handle_vblank - handle a vblank event | ||
| 689 | * @dev: DRM device | ||
| 690 | * @crtc: where this event occurred | ||
| 691 | * | ||
| 692 | * Drivers should call this routine in their vblank interrupt handlers to | ||
| 693 | * update the vblank counter and send any signals that may be pending. | ||
| 694 | */ | ||
| 695 | void drm_handle_vblank(struct drm_device *dev, int crtc) | ||
| 696 | { | ||
| 697 | atomic_inc(&dev->_vblank_count[crtc]); | ||
| 698 | DRM_WAKEUP(&dev->vbl_queue[crtc]); | ||
| 699 | drm_vbl_send_signals(dev, crtc); | ||
| 700 | } | ||
| 701 | EXPORT_SYMBOL(drm_handle_vblank); | ||
| 393 | 702 | ||
| 394 | /** | 703 | /** |
| 395 | * Tasklet wrapper function. | 704 | * Tasklet wrapper function. |
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 29115450ee46..63c6803d471b 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c | |||
| @@ -673,7 +673,7 @@ static int i915_getparam(struct drm_device *dev, void *data, | |||
| 673 | 673 | ||
| 674 | switch (param->param) { | 674 | switch (param->param) { |
| 675 | case I915_PARAM_IRQ_ACTIVE: | 675 | case I915_PARAM_IRQ_ACTIVE: |
| 676 | value = dev->irq_enabled; | 676 | value = dev->pdev->irq ? 1 : 0; |
| 677 | break; | 677 | break; |
| 678 | case I915_PARAM_ALLOW_BATCHBUFFER: | 678 | case I915_PARAM_ALLOW_BATCHBUFFER: |
| 679 | value = dev_priv->allow_batchbuffer ? 1 : 0; | 679 | value = dev_priv->allow_batchbuffer ? 1 : 0; |
| @@ -808,7 +808,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) | |||
| 808 | * and the registers being closely associated. | 808 | * and the registers being closely associated. |
| 809 | */ | 809 | */ |
| 810 | if (!IS_I945G(dev) && !IS_I945GM(dev)) | 810 | if (!IS_I945G(dev) && !IS_I945GM(dev)) |
| 811 | pci_enable_msi(dev->pdev); | 811 | if (pci_enable_msi(dev->pdev)) |
| 812 | DRM_ERROR("failed to enable MSI\n"); | ||
| 812 | 813 | ||
| 813 | intel_opregion_init(dev); | 814 | intel_opregion_init(dev); |
| 814 | 815 | ||
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index eff66ed3e58e..37af03f4db36 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c | |||
| @@ -85,10 +85,8 @@ static struct drm_driver driver = { | |||
| 85 | /* don't use mtrr's here, the Xserver or user space app should | 85 | /* don't use mtrr's here, the Xserver or user space app should |
| 86 | * deal with them for intel hardware. | 86 | * deal with them for intel hardware. |
| 87 | */ | 87 | */ |
| 88 | .driver_features = | 88 | .driver_features = DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | |
| 89 | DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | /* DRIVER_USE_MTRR |*/ | 89 | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED, |
| 90 | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL | | ||
| 91 | DRIVER_IRQ_VBL2, | ||
| 92 | .load = i915_driver_load, | 90 | .load = i915_driver_load, |
| 93 | .unload = i915_driver_unload, | 91 | .unload = i915_driver_unload, |
| 94 | .lastclose = i915_driver_lastclose, | 92 | .lastclose = i915_driver_lastclose, |
| @@ -96,8 +94,9 @@ static struct drm_driver driver = { | |||
| 96 | .suspend = i915_suspend, | 94 | .suspend = i915_suspend, |
| 97 | .resume = i915_resume, | 95 | .resume = i915_resume, |
| 98 | .device_is_agp = i915_driver_device_is_agp, | 96 | .device_is_agp = i915_driver_device_is_agp, |
| 99 | .vblank_wait = i915_driver_vblank_wait, | 97 | .get_vblank_counter = i915_get_vblank_counter, |
| 100 | .vblank_wait2 = i915_driver_vblank_wait2, | 98 | .enable_vblank = i915_enable_vblank, |
| 99 | .disable_vblank = i915_disable_vblank, | ||
| 101 | .irq_preinstall = i915_driver_irq_preinstall, | 100 | .irq_preinstall = i915_driver_irq_preinstall, |
| 102 | .irq_postinstall = i915_driver_irq_postinstall, | 101 | .irq_postinstall = i915_driver_irq_postinstall, |
| 103 | .irq_uninstall = i915_driver_irq_uninstall, | 102 | .irq_uninstall = i915_driver_irq_uninstall, |
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 71326ca9367a..d1a02bead458 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
| @@ -83,10 +83,15 @@ struct mem_block { | |||
| 83 | typedef struct _drm_i915_vbl_swap { | 83 | typedef struct _drm_i915_vbl_swap { |
| 84 | struct list_head head; | 84 | struct list_head head; |
| 85 | drm_drawable_t drw_id; | 85 | drm_drawable_t drw_id; |
| 86 | unsigned int pipe; | 86 | unsigned int plane; |
| 87 | unsigned int sequence; | 87 | unsigned int sequence; |
| 88 | } drm_i915_vbl_swap_t; | 88 | } drm_i915_vbl_swap_t; |
| 89 | 89 | ||
| 90 | struct opregion_header; | ||
| 91 | struct opregion_acpi; | ||
| 92 | struct opregion_swsci; | ||
| 93 | struct opregion_asle; | ||
| 94 | |||
| 90 | struct intel_opregion { | 95 | struct intel_opregion { |
| 91 | struct opregion_header *header; | 96 | struct opregion_header *header; |
| 92 | struct opregion_acpi *acpi; | 97 | struct opregion_acpi *acpi; |
| @@ -105,7 +110,7 @@ typedef struct drm_i915_private { | |||
| 105 | drm_dma_handle_t *status_page_dmah; | 110 | drm_dma_handle_t *status_page_dmah; |
| 106 | void *hw_status_page; | 111 | void *hw_status_page; |
| 107 | dma_addr_t dma_status_page; | 112 | dma_addr_t dma_status_page; |
| 108 | unsigned long counter; | 113 | uint32_t counter; |
| 109 | unsigned int status_gfx_addr; | 114 | unsigned int status_gfx_addr; |
| 110 | drm_local_map_t hws_map; | 115 | drm_local_map_t hws_map; |
| 111 | 116 | ||
| @@ -247,16 +252,17 @@ extern int i915_irq_emit(struct drm_device *dev, void *data, | |||
| 247 | extern int i915_irq_wait(struct drm_device *dev, void *data, | 252 | extern int i915_irq_wait(struct drm_device *dev, void *data, |
| 248 | struct drm_file *file_priv); | 253 | struct drm_file *file_priv); |
| 249 | 254 | ||
| 250 | extern int i915_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence); | ||
| 251 | extern int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence); | ||
| 252 | extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS); | 255 | extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS); |
| 253 | extern void i915_driver_irq_preinstall(struct drm_device * dev); | 256 | extern void i915_driver_irq_preinstall(struct drm_device * dev); |
| 254 | extern void i915_driver_irq_postinstall(struct drm_device * dev); | 257 | extern int i915_driver_irq_postinstall(struct drm_device *dev); |
| 255 | extern void i915_driver_irq_uninstall(struct drm_device * dev); | 258 | extern void i915_driver_irq_uninstall(struct drm_device * dev); |
| 256 | extern int i915_vblank_pipe_set(struct drm_device *dev, void *data, | 259 | extern int i915_vblank_pipe_set(struct drm_device *dev, void *data, |
| 257 | struct drm_file *file_priv); | 260 | struct drm_file *file_priv); |
| 258 | extern int i915_vblank_pipe_get(struct drm_device *dev, void *data, | 261 | extern int i915_vblank_pipe_get(struct drm_device *dev, void *data, |
| 259 | struct drm_file *file_priv); | 262 | struct drm_file *file_priv); |
| 263 | extern int i915_enable_vblank(struct drm_device *dev, int crtc); | ||
| 264 | extern void i915_disable_vblank(struct drm_device *dev, int crtc); | ||
| 265 | extern u32 i915_get_vblank_counter(struct drm_device *dev, int crtc); | ||
| 260 | extern int i915_vblank_swap(struct drm_device *dev, void *data, | 266 | extern int i915_vblank_swap(struct drm_device *dev, void *data, |
| 261 | struct drm_file *file_priv); | 267 | struct drm_file *file_priv); |
| 262 | extern void i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask); | 268 | extern void i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask); |
| @@ -278,6 +284,10 @@ extern void i915_mem_release(struct drm_device * dev, | |||
| 278 | extern int i915_save_state(struct drm_device *dev); | 284 | extern int i915_save_state(struct drm_device *dev); |
| 279 | extern int i915_restore_state(struct drm_device *dev); | 285 | extern int i915_restore_state(struct drm_device *dev); |
| 280 | 286 | ||
| 287 | /* i915_suspend.c */ | ||
| 288 | extern int i915_save_state(struct drm_device *dev); | ||
| 289 | extern int i915_restore_state(struct drm_device *dev); | ||
| 290 | |||
| 281 | /* i915_opregion.c */ | 291 | /* i915_opregion.c */ |
| 282 | extern int intel_opregion_init(struct drm_device *dev); | 292 | extern int intel_opregion_init(struct drm_device *dev); |
| 283 | extern void intel_opregion_free(struct drm_device *dev); | 293 | extern void intel_opregion_free(struct drm_device *dev); |
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index ae7d3a82a6d1..f8759597233b 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c | |||
| @@ -35,9 +35,8 @@ | |||
| 35 | 35 | ||
| 36 | /** These are the interrupts used by the driver */ | 36 | /** These are the interrupts used by the driver */ |
| 37 | #define I915_INTERRUPT_ENABLE_MASK (I915_USER_INTERRUPT | \ | 37 | #define I915_INTERRUPT_ENABLE_MASK (I915_USER_INTERRUPT | \ |
| 38 | I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT | \ | ||
| 39 | I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT | \ | ||
| 40 | I915_ASLE_INTERRUPT | \ | 38 | I915_ASLE_INTERRUPT | \ |
| 39 | I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | \ | ||
| 41 | I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) | 40 | I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) |
| 42 | 41 | ||
| 43 | void | 42 | void |
| @@ -61,6 +60,64 @@ i915_disable_irq(drm_i915_private_t *dev_priv, u32 mask) | |||
| 61 | } | 60 | } |
| 62 | 61 | ||
| 63 | /** | 62 | /** |
| 63 | * i915_get_pipe - return the the pipe associated with a given plane | ||
| 64 | * @dev: DRM device | ||
| 65 | * @plane: plane to look for | ||
| 66 | * | ||
| 67 | * The Intel Mesa & 2D drivers call the vblank routines with a plane number | ||
| 68 | * rather than a pipe number, since they may not always be equal. This routine | ||
| 69 | * maps the given @plane back to a pipe number. | ||
| 70 | */ | ||
| 71 | static int | ||
| 72 | i915_get_pipe(struct drm_device *dev, int plane) | ||
| 73 | { | ||
| 74 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | ||
| 75 | u32 dspcntr; | ||
| 76 | |||
| 77 | dspcntr = plane ? I915_READ(DSPBCNTR) : I915_READ(DSPACNTR); | ||
| 78 | |||
| 79 | return dspcntr & DISPPLANE_SEL_PIPE_MASK ? 1 : 0; | ||
| 80 | } | ||
| 81 | |||
| 82 | /** | ||
| 83 | * i915_get_plane - return the the plane associated with a given pipe | ||
| 84 | * @dev: DRM device | ||
| 85 | * @pipe: pipe to look for | ||
| 86 | * | ||
| 87 | * The Intel Mesa & 2D drivers call the vblank routines with a plane number | ||
| 88 | * rather than a plane number, since they may not always be equal. This routine | ||
| 89 | * maps the given @pipe back to a plane number. | ||
| 90 | */ | ||
| 91 | static int | ||
| 92 | i915_get_plane(struct drm_device *dev, int pipe) | ||
| 93 | { | ||
| 94 | if (i915_get_pipe(dev, 0) == pipe) | ||
| 95 | return 0; | ||
| 96 | return 1; | ||
| 97 | } | ||
| 98 | |||
| 99 | /** | ||
| 100 | * i915_pipe_enabled - check if a pipe is enabled | ||
| 101 | * @dev: DRM device | ||
| 102 | * @pipe: pipe to check | ||
| 103 | * | ||
| 104 | * Reading certain registers when the pipe is disabled can hang the chip. | ||
| 105 | * Use this routine to make sure the PLL is running and the pipe is active | ||
| 106 | * before reading such registers if unsure. | ||
| 107 | */ | ||
| 108 | static int | ||
| 109 | i915_pipe_enabled(struct drm_device *dev, int pipe) | ||
| 110 | { | ||
| 111 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | ||
| 112 | unsigned long pipeconf = pipe ? PIPEBCONF : PIPEACONF; | ||
| 113 | |||
| 114 | if (I915_READ(pipeconf) & PIPEACONF_ENABLE) | ||
| 115 | return 1; | ||
| 116 | |||
| 117 | return 0; | ||
| 118 | } | ||
| 119 | |||
| 120 | /** | ||
| 64 | * Emit blits for scheduled buffer swaps. | 121 | * Emit blits for scheduled buffer swaps. |
| 65 | * | 122 | * |
| 66 | * This function will be called with the HW lock held. | 123 | * This function will be called with the HW lock held. |
| @@ -71,8 +128,7 @@ static void i915_vblank_tasklet(struct drm_device *dev) | |||
| 71 | unsigned long irqflags; | 128 | unsigned long irqflags; |
| 72 | struct list_head *list, *tmp, hits, *hit; | 129 | struct list_head *list, *tmp, hits, *hit; |
| 73 | int nhits, nrects, slice[2], upper[2], lower[2], i; | 130 | int nhits, nrects, slice[2], upper[2], lower[2], i; |
| 74 | unsigned counter[2] = { atomic_read(&dev->vbl_received), | 131 | unsigned counter[2]; |
| 75 | atomic_read(&dev->vbl_received2) }; | ||
| 76 | struct drm_drawable_info *drw; | 132 | struct drm_drawable_info *drw; |
| 77 | drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; | 133 | drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; |
| 78 | u32 cpp = dev_priv->cpp; | 134 | u32 cpp = dev_priv->cpp; |
| @@ -94,6 +150,9 @@ static void i915_vblank_tasklet(struct drm_device *dev) | |||
| 94 | src_pitch >>= 2; | 150 | src_pitch >>= 2; |
| 95 | } | 151 | } |
| 96 | 152 | ||
| 153 | counter[0] = drm_vblank_count(dev, 0); | ||
| 154 | counter[1] = drm_vblank_count(dev, 1); | ||
| 155 | |||
| 97 | DRM_DEBUG("\n"); | 156 | DRM_DEBUG("\n"); |
| 98 | 157 | ||
| 99 | INIT_LIST_HEAD(&hits); | 158 | INIT_LIST_HEAD(&hits); |
| @@ -106,12 +165,14 @@ static void i915_vblank_tasklet(struct drm_device *dev) | |||
| 106 | list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) { | 165 | list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) { |
| 107 | drm_i915_vbl_swap_t *vbl_swap = | 166 | drm_i915_vbl_swap_t *vbl_swap = |
| 108 | list_entry(list, drm_i915_vbl_swap_t, head); | 167 | list_entry(list, drm_i915_vbl_swap_t, head); |
| 168 | int pipe = i915_get_pipe(dev, vbl_swap->plane); | ||
| 109 | 169 | ||
| 110 | if ((counter[vbl_swap->pipe] - vbl_swap->sequence) > (1<<23)) | 170 | if ((counter[pipe] - vbl_swap->sequence) > (1<<23)) |
| 111 | continue; | 171 | continue; |
| 112 | 172 | ||
| 113 | list_del(list); | 173 | list_del(list); |
| 114 | dev_priv->swaps_pending--; | 174 | dev_priv->swaps_pending--; |
| 175 | drm_vblank_put(dev, pipe); | ||
| 115 | 176 | ||
| 116 | spin_unlock(&dev_priv->swaps_lock); | 177 | spin_unlock(&dev_priv->swaps_lock); |
| 117 | spin_lock(&dev->drw_lock); | 178 | spin_lock(&dev->drw_lock); |
| @@ -204,7 +265,7 @@ static void i915_vblank_tasklet(struct drm_device *dev) | |||
| 204 | drm_i915_vbl_swap_t *swap_hit = | 265 | drm_i915_vbl_swap_t *swap_hit = |
| 205 | list_entry(hit, drm_i915_vbl_swap_t, head); | 266 | list_entry(hit, drm_i915_vbl_swap_t, head); |
| 206 | struct drm_clip_rect *rect; | 267 | struct drm_clip_rect *rect; |
| 207 | int num_rects, pipe; | 268 | int num_rects, plane; |
| 208 | unsigned short top, bottom; | 269 | unsigned short top, bottom; |
| 209 | 270 | ||
| 210 | drw = drm_get_drawable_info(dev, swap_hit->drw_id); | 271 | drw = drm_get_drawable_info(dev, swap_hit->drw_id); |
| @@ -213,9 +274,9 @@ static void i915_vblank_tasklet(struct drm_device *dev) | |||
| 213 | continue; | 274 | continue; |
| 214 | 275 | ||
| 215 | rect = drw->rects; | 276 | rect = drw->rects; |
| 216 | pipe = swap_hit->pipe; | 277 | plane = swap_hit->plane; |
| 217 | top = upper[pipe]; | 278 | top = upper[plane]; |
| 218 | bottom = lower[pipe]; | 279 | bottom = lower[plane]; |
| 219 | 280 | ||
| 220 | for (num_rects = drw->num_rects; num_rects--; rect++) { | 281 | for (num_rects = drw->num_rects; num_rects--; rect++) { |
| 221 | int y1 = max(rect->y1, top); | 282 | int y1 = max(rect->y1, top); |
| @@ -252,22 +313,54 @@ static void i915_vblank_tasklet(struct drm_device *dev) | |||
| 252 | } | 313 | } |
| 253 | } | 314 | } |
| 254 | 315 | ||
| 316 | u32 i915_get_vblank_counter(struct drm_device *dev, int plane) | ||
| 317 | { | ||
| 318 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | ||
| 319 | unsigned long high_frame; | ||
| 320 | unsigned long low_frame; | ||
| 321 | u32 high1, high2, low, count; | ||
| 322 | int pipe; | ||
| 323 | |||
| 324 | pipe = i915_get_pipe(dev, plane); | ||
| 325 | high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH; | ||
| 326 | low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL; | ||
| 327 | |||
| 328 | if (!i915_pipe_enabled(dev, pipe)) { | ||
| 329 | DRM_ERROR("trying to get vblank count for disabled pipe %d\n", pipe); | ||
| 330 | return 0; | ||
| 331 | } | ||
| 332 | |||
| 333 | /* | ||
| 334 | * High & low register fields aren't synchronized, so make sure | ||
| 335 | * we get a low value that's stable across two reads of the high | ||
| 336 | * register. | ||
| 337 | */ | ||
| 338 | do { | ||
| 339 | high1 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >> | ||
| 340 | PIPE_FRAME_HIGH_SHIFT); | ||
| 341 | low = ((I915_READ(low_frame) & PIPE_FRAME_LOW_MASK) >> | ||
| 342 | PIPE_FRAME_LOW_SHIFT); | ||
| 343 | high2 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >> | ||
| 344 | PIPE_FRAME_HIGH_SHIFT); | ||
| 345 | } while (high1 != high2); | ||
| 346 | |||
| 347 | count = (high1 << 8) | low; | ||
| 348 | |||
| 349 | return count; | ||
| 350 | } | ||
| 351 | |||
| 255 | irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) | 352 | irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) |
| 256 | { | 353 | { |
| 257 | struct drm_device *dev = (struct drm_device *) arg; | 354 | struct drm_device *dev = (struct drm_device *) arg; |
| 258 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 355 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
| 259 | u32 pipea_stats, pipeb_stats; | ||
| 260 | u32 iir; | 356 | u32 iir; |
| 261 | 357 | u32 pipea_stats, pipeb_stats; | |
| 262 | pipea_stats = I915_READ(PIPEASTAT); | 358 | int vblank = 0; |
| 263 | pipeb_stats = I915_READ(PIPEBSTAT); | ||
| 264 | 359 | ||
| 265 | if (dev->pdev->msi_enabled) | 360 | if (dev->pdev->msi_enabled) |
| 266 | I915_WRITE(IMR, ~0); | 361 | I915_WRITE(IMR, ~0); |
| 267 | iir = I915_READ(IIR); | 362 | iir = I915_READ(IIR); |
| 268 | 363 | ||
| 269 | DRM_DEBUG("iir=%08x\n", iir); | ||
| 270 | |||
| 271 | if (iir == 0) { | 364 | if (iir == 0) { |
| 272 | if (dev->pdev->msi_enabled) { | 365 | if (dev->pdev->msi_enabled) { |
| 273 | I915_WRITE(IMR, dev_priv->irq_mask_reg); | 366 | I915_WRITE(IMR, dev_priv->irq_mask_reg); |
| @@ -276,48 +369,56 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) | |||
| 276 | return IRQ_NONE; | 369 | return IRQ_NONE; |
| 277 | } | 370 | } |
| 278 | 371 | ||
| 279 | I915_WRITE(PIPEASTAT, pipea_stats); | 372 | /* |
| 280 | I915_WRITE(PIPEBSTAT, pipeb_stats); | 373 | * Clear the PIPE(A|B)STAT regs before the IIR otherwise |
| 281 | 374 | * we may get extra interrupts. | |
| 282 | I915_WRITE(IIR, iir); | 375 | */ |
| 283 | if (dev->pdev->msi_enabled) | 376 | if (iir & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) { |
| 284 | I915_WRITE(IMR, dev_priv->irq_mask_reg); | 377 | pipea_stats = I915_READ(PIPEASTAT); |
| 285 | (void) I915_READ(IIR); /* Flush posted writes */ | 378 | if (!(dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A)) |
| 286 | 379 | pipea_stats &= ~(PIPE_START_VBLANK_INTERRUPT_ENABLE | | |
| 287 | dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); | 380 | PIPE_VBLANK_INTERRUPT_ENABLE); |
| 288 | 381 | else if (pipea_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS| | |
| 289 | if (iir & I915_USER_INTERRUPT) | 382 | PIPE_VBLANK_INTERRUPT_STATUS)) { |
| 290 | DRM_WAKEUP(&dev_priv->irq_queue); | 383 | vblank++; |
| 291 | 384 | drm_handle_vblank(dev, i915_get_plane(dev, 0)); | |
| 292 | if (iir & (I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT | | 385 | } |
| 293 | I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT)) { | ||
| 294 | int vblank_pipe = dev_priv->vblank_pipe; | ||
| 295 | |||
| 296 | if ((vblank_pipe & | ||
| 297 | (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) | ||
| 298 | == (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) { | ||
| 299 | if (iir & I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT) | ||
| 300 | atomic_inc(&dev->vbl_received); | ||
| 301 | if (iir & I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT) | ||
| 302 | atomic_inc(&dev->vbl_received2); | ||
| 303 | } else if (((iir & I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT) && | ||
| 304 | (vblank_pipe & DRM_I915_VBLANK_PIPE_A)) || | ||
| 305 | ((iir & I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT) && | ||
| 306 | (vblank_pipe & DRM_I915_VBLANK_PIPE_B))) | ||
| 307 | atomic_inc(&dev->vbl_received); | ||
| 308 | 386 | ||
| 309 | DRM_WAKEUP(&dev->vbl_queue); | 387 | I915_WRITE(PIPEASTAT, pipea_stats); |
| 310 | drm_vbl_send_signals(dev); | 388 | } |
| 389 | if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) { | ||
| 390 | pipeb_stats = I915_READ(PIPEBSTAT); | ||
| 391 | /* Ack the event */ | ||
| 392 | I915_WRITE(PIPEBSTAT, pipeb_stats); | ||
| 393 | |||
| 394 | /* The vblank interrupt gets enabled even if we didn't ask for | ||
| 395 | it, so make sure it's shut down again */ | ||
| 396 | if (!(dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B)) | ||
| 397 | pipeb_stats &= ~(PIPE_START_VBLANK_INTERRUPT_ENABLE | | ||
| 398 | PIPE_VBLANK_INTERRUPT_ENABLE); | ||
| 399 | else if (pipeb_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS| | ||
| 400 | PIPE_VBLANK_INTERRUPT_STATUS)) { | ||
| 401 | vblank++; | ||
| 402 | drm_handle_vblank(dev, i915_get_plane(dev, 1)); | ||
| 403 | } | ||
| 311 | 404 | ||
| 312 | if (dev_priv->swaps_pending > 0) | 405 | if (pipeb_stats & I915_LEGACY_BLC_EVENT_STATUS) |
| 313 | drm_locked_tasklet(dev, i915_vblank_tasklet); | 406 | opregion_asle_intr(dev); |
| 407 | I915_WRITE(PIPEBSTAT, pipeb_stats); | ||
| 314 | } | 408 | } |
| 315 | 409 | ||
| 316 | if (iir & I915_ASLE_INTERRUPT) | 410 | if (iir & I915_ASLE_INTERRUPT) |
| 317 | opregion_asle_intr(dev); | 411 | opregion_asle_intr(dev); |
| 318 | 412 | ||
| 319 | if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) | 413 | dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); |
| 320 | opregion_asle_intr(dev); | 414 | |
| 415 | if (dev->pdev->msi_enabled) | ||
| 416 | I915_WRITE(IMR, dev_priv->irq_mask_reg); | ||
| 417 | I915_WRITE(IIR, iir); | ||
| 418 | (void) I915_READ(IIR); | ||
| 419 | |||
| 420 | if (vblank && dev_priv->swaps_pending > 0) | ||
| 421 | drm_locked_tasklet(dev, i915_vblank_tasklet); | ||
| 321 | 422 | ||
| 322 | return IRQ_HANDLED; | 423 | return IRQ_HANDLED; |
| 323 | } | 424 | } |
| @@ -358,7 +459,7 @@ static void i915_user_irq_get(struct drm_device *dev) | |||
| 358 | spin_unlock(&dev_priv->user_irq_lock); | 459 | spin_unlock(&dev_priv->user_irq_lock); |
| 359 | } | 460 | } |
| 360 | 461 | ||
| 361 | static void i915_user_irq_put(struct drm_device *dev) | 462 | void i915_user_irq_put(struct drm_device *dev) |
| 362 | { | 463 | { |
| 363 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 464 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
| 364 | 465 | ||
| @@ -395,41 +496,10 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr) | |||
| 395 | } | 496 | } |
| 396 | 497 | ||
| 397 | dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); | 498 | dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); |
| 398 | return ret; | ||
| 399 | } | ||
| 400 | |||
| 401 | static int i915_driver_vblank_do_wait(struct drm_device *dev, unsigned int *sequence, | ||
| 402 | atomic_t *counter) | ||
| 403 | { | ||
| 404 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
| 405 | unsigned int cur_vblank; | ||
| 406 | int ret = 0; | ||
| 407 | |||
| 408 | if (!dev_priv) { | ||
| 409 | DRM_ERROR("called with no initialization\n"); | ||
| 410 | return -EINVAL; | ||
| 411 | } | ||
| 412 | |||
| 413 | DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, | ||
| 414 | (((cur_vblank = atomic_read(counter)) | ||
| 415 | - *sequence) <= (1<<23))); | ||
| 416 | |||
| 417 | *sequence = cur_vblank; | ||
| 418 | 499 | ||
| 419 | return ret; | 500 | return ret; |
| 420 | } | 501 | } |
| 421 | 502 | ||
| 422 | |||
| 423 | int i915_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence) | ||
| 424 | { | ||
| 425 | return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received); | ||
| 426 | } | ||
| 427 | |||
| 428 | int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence) | ||
| 429 | { | ||
| 430 | return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received2); | ||
| 431 | } | ||
| 432 | |||
| 433 | /* Needs the lock as it touches the ring. | 503 | /* Needs the lock as it touches the ring. |
| 434 | */ | 504 | */ |
| 435 | int i915_irq_emit(struct drm_device *dev, void *data, | 505 | int i915_irq_emit(struct drm_device *dev, void *data, |
| @@ -472,40 +542,88 @@ int i915_irq_wait(struct drm_device *dev, void *data, | |||
| 472 | return i915_wait_irq(dev, irqwait->irq_seq); | 542 | return i915_wait_irq(dev, irqwait->irq_seq); |
| 473 | } | 543 | } |
| 474 | 544 | ||
| 545 | int i915_enable_vblank(struct drm_device *dev, int plane) | ||
| 546 | { | ||
| 547 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | ||
| 548 | int pipe = i915_get_pipe(dev, plane); | ||
| 549 | u32 pipestat_reg = 0; | ||
| 550 | u32 pipestat; | ||
| 551 | |||
| 552 | switch (pipe) { | ||
| 553 | case 0: | ||
| 554 | pipestat_reg = PIPEASTAT; | ||
| 555 | i915_enable_irq(dev_priv, I915_DISPLAY_PIPE_A_EVENT_INTERRUPT); | ||
| 556 | break; | ||
| 557 | case 1: | ||
| 558 | pipestat_reg = PIPEBSTAT; | ||
| 559 | i915_enable_irq(dev_priv, I915_DISPLAY_PIPE_B_EVENT_INTERRUPT); | ||
| 560 | break; | ||
| 561 | default: | ||
| 562 | DRM_ERROR("tried to enable vblank on non-existent pipe %d\n", | ||
| 563 | pipe); | ||
| 564 | break; | ||
| 565 | } | ||
| 566 | |||
| 567 | if (pipestat_reg) { | ||
| 568 | pipestat = I915_READ(pipestat_reg); | ||
| 569 | if (IS_I965G(dev)) | ||
| 570 | pipestat |= PIPE_START_VBLANK_INTERRUPT_ENABLE; | ||
| 571 | else | ||
| 572 | pipestat |= PIPE_VBLANK_INTERRUPT_ENABLE; | ||
| 573 | /* Clear any stale interrupt status */ | ||
| 574 | pipestat |= (PIPE_START_VBLANK_INTERRUPT_STATUS | | ||
| 575 | PIPE_VBLANK_INTERRUPT_STATUS); | ||
| 576 | I915_WRITE(pipestat_reg, pipestat); | ||
| 577 | } | ||
| 578 | |||
| 579 | return 0; | ||
| 580 | } | ||
| 581 | |||
| 582 | void i915_disable_vblank(struct drm_device *dev, int plane) | ||
| 583 | { | ||
| 584 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | ||
| 585 | int pipe = i915_get_pipe(dev, plane); | ||
| 586 | u32 pipestat_reg = 0; | ||
| 587 | u32 pipestat; | ||
| 588 | |||
| 589 | switch (pipe) { | ||
| 590 | case 0: | ||
| 591 | pipestat_reg = PIPEASTAT; | ||
| 592 | i915_disable_irq(dev_priv, I915_DISPLAY_PIPE_A_EVENT_INTERRUPT); | ||
| 593 | break; | ||
| 594 | case 1: | ||
| 595 | pipestat_reg = PIPEBSTAT; | ||
| 596 | i915_disable_irq(dev_priv, I915_DISPLAY_PIPE_B_EVENT_INTERRUPT); | ||
| 597 | break; | ||
| 598 | default: | ||
| 599 | DRM_ERROR("tried to disable vblank on non-existent pipe %d\n", | ||
| 600 | pipe); | ||
| 601 | break; | ||
| 602 | } | ||
| 603 | |||
| 604 | if (pipestat_reg) { | ||
| 605 | pipestat = I915_READ(pipestat_reg); | ||
| 606 | pipestat &= ~(PIPE_START_VBLANK_INTERRUPT_ENABLE | | ||
| 607 | PIPE_VBLANK_INTERRUPT_ENABLE); | ||
| 608 | /* Clear any stale interrupt status */ | ||
| 609 | pipestat |= (PIPE_START_VBLANK_INTERRUPT_STATUS | | ||
| 610 | PIPE_VBLANK_INTERRUPT_STATUS); | ||
| 611 | I915_WRITE(pipestat_reg, pipestat); | ||
| 612 | } | ||
| 613 | } | ||
| 614 | |||
| 475 | /* Set the vblank monitor pipe | 615 | /* Set the vblank monitor pipe |
| 476 | */ | 616 | */ |
| 477 | int i915_vblank_pipe_set(struct drm_device *dev, void *data, | 617 | int i915_vblank_pipe_set(struct drm_device *dev, void *data, |
| 478 | struct drm_file *file_priv) | 618 | struct drm_file *file_priv) |
| 479 | { | 619 | { |
| 480 | drm_i915_private_t *dev_priv = dev->dev_private; | 620 | drm_i915_private_t *dev_priv = dev->dev_private; |
| 481 | drm_i915_vblank_pipe_t *pipe = data; | ||
| 482 | u32 enable_mask = 0, disable_mask = 0; | ||
| 483 | 621 | ||
| 484 | if (!dev_priv) { | 622 | if (!dev_priv) { |
| 485 | DRM_ERROR("called with no initialization\n"); | 623 | DRM_ERROR("called with no initialization\n"); |
| 486 | return -EINVAL; | 624 | return -EINVAL; |
| 487 | } | 625 | } |
| 488 | 626 | ||
| 489 | if (pipe->pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) { | ||
| 490 | DRM_ERROR("called with invalid pipe 0x%x\n", pipe->pipe); | ||
| 491 | return -EINVAL; | ||
| 492 | } | ||
| 493 | |||
| 494 | if (pipe->pipe & DRM_I915_VBLANK_PIPE_A) | ||
| 495 | enable_mask |= I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT; | ||
| 496 | else | ||
| 497 | disable_mask |= I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT; | ||
| 498 | |||
| 499 | if (pipe->pipe & DRM_I915_VBLANK_PIPE_B) | ||
| 500 | enable_mask |= I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; | ||
| 501 | else | ||
| 502 | disable_mask |= I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; | ||
| 503 | |||
| 504 | i915_enable_irq(dev_priv, enable_mask); | ||
| 505 | i915_disable_irq(dev_priv, disable_mask); | ||
| 506 | |||
| 507 | dev_priv->vblank_pipe = pipe->pipe; | ||
| 508 | |||
| 509 | return 0; | 627 | return 0; |
| 510 | } | 628 | } |
| 511 | 629 | ||
| @@ -514,19 +632,13 @@ int i915_vblank_pipe_get(struct drm_device *dev, void *data, | |||
| 514 | { | 632 | { |
| 515 | drm_i915_private_t *dev_priv = dev->dev_private; | 633 | drm_i915_private_t *dev_priv = dev->dev_private; |
| 516 | drm_i915_vblank_pipe_t *pipe = data; | 634 | drm_i915_vblank_pipe_t *pipe = data; |
| 517 | u16 flag; | ||
| 518 | 635 | ||
| 519 | if (!dev_priv) { | 636 | if (!dev_priv) { |
| 520 | DRM_ERROR("called with no initialization\n"); | 637 | DRM_ERROR("called with no initialization\n"); |
| 521 | return -EINVAL; | 638 | return -EINVAL; |
| 522 | } | 639 | } |
| 523 | 640 | ||
| 524 | flag = I915_READ(IMR); | 641 | pipe->pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; |
| 525 | pipe->pipe = 0; | ||
| 526 | if (flag & I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT) | ||
| 527 | pipe->pipe |= DRM_I915_VBLANK_PIPE_A; | ||
| 528 | if (flag & I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT) | ||
| 529 | pipe->pipe |= DRM_I915_VBLANK_PIPE_B; | ||
| 530 | 642 | ||
| 531 | return 0; | 643 | return 0; |
| 532 | } | 644 | } |
| @@ -540,9 +652,10 @@ int i915_vblank_swap(struct drm_device *dev, void *data, | |||
| 540 | drm_i915_private_t *dev_priv = dev->dev_private; | 652 | drm_i915_private_t *dev_priv = dev->dev_private; |
| 541 | drm_i915_vblank_swap_t *swap = data; | 653 | drm_i915_vblank_swap_t *swap = data; |
| 542 | drm_i915_vbl_swap_t *vbl_swap; | 654 | drm_i915_vbl_swap_t *vbl_swap; |
| 543 | unsigned int pipe, seqtype, curseq; | 655 | unsigned int pipe, seqtype, curseq, plane; |
| 544 | unsigned long irqflags; | 656 | unsigned long irqflags; |
| 545 | struct list_head *list; | 657 | struct list_head *list; |
| 658 | int ret; | ||
| 546 | 659 | ||
| 547 | if (!dev_priv) { | 660 | if (!dev_priv) { |
| 548 | DRM_ERROR("%s called with no initialization\n", __func__); | 661 | DRM_ERROR("%s called with no initialization\n", __func__); |
| @@ -560,7 +673,8 @@ int i915_vblank_swap(struct drm_device *dev, void *data, | |||
| 560 | return -EINVAL; | 673 | return -EINVAL; |
| 561 | } | 674 | } |
| 562 | 675 | ||
| 563 | pipe = (swap->seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0; | 676 | plane = (swap->seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0; |
| 677 | pipe = i915_get_pipe(dev, plane); | ||
| 564 | 678 | ||
| 565 | seqtype = swap->seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE); | 679 | seqtype = swap->seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE); |
| 566 | 680 | ||
| @@ -579,7 +693,14 @@ int i915_vblank_swap(struct drm_device *dev, void *data, | |||
| 579 | 693 | ||
| 580 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | 694 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); |
| 581 | 695 | ||
| 582 | curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received); | 696 | /* |
| 697 | * We take the ref here and put it when the swap actually completes | ||
| 698 | * in the tasklet. | ||
| 699 | */ | ||
| 700 | ret = drm_vblank_get(dev, pipe); | ||
| 701 | if (ret) | ||
| 702 | return ret; | ||
| 703 | curseq = drm_vblank_count(dev, pipe); | ||
| 583 | 704 | ||
| 584 | if (seqtype == _DRM_VBLANK_RELATIVE) | 705 | if (seqtype == _DRM_VBLANK_RELATIVE) |
| 585 | swap->sequence += curseq; | 706 | swap->sequence += curseq; |
| @@ -589,6 +710,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data, | |||
| 589 | swap->sequence = curseq + 1; | 710 | swap->sequence = curseq + 1; |
| 590 | } else { | 711 | } else { |
| 591 | DRM_DEBUG("Missed target sequence\n"); | 712 | DRM_DEBUG("Missed target sequence\n"); |
| 713 | drm_vblank_put(dev, pipe); | ||
| 592 | return -EINVAL; | 714 | return -EINVAL; |
| 593 | } | 715 | } |
| 594 | } | 716 | } |
| @@ -599,7 +721,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data, | |||
| 599 | vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head); | 721 | vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head); |
| 600 | 722 | ||
| 601 | if (vbl_swap->drw_id == swap->drawable && | 723 | if (vbl_swap->drw_id == swap->drawable && |
| 602 | vbl_swap->pipe == pipe && | 724 | vbl_swap->plane == plane && |
| 603 | vbl_swap->sequence == swap->sequence) { | 725 | vbl_swap->sequence == swap->sequence) { |
| 604 | spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); | 726 | spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); |
| 605 | DRM_DEBUG("Already scheduled\n"); | 727 | DRM_DEBUG("Already scheduled\n"); |
| @@ -611,6 +733,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data, | |||
| 611 | 733 | ||
| 612 | if (dev_priv->swaps_pending >= 100) { | 734 | if (dev_priv->swaps_pending >= 100) { |
| 613 | DRM_DEBUG("Too many swaps queued\n"); | 735 | DRM_DEBUG("Too many swaps queued\n"); |
| 736 | drm_vblank_put(dev, pipe); | ||
| 614 | return -EBUSY; | 737 | return -EBUSY; |
| 615 | } | 738 | } |
| 616 | 739 | ||
| @@ -618,13 +741,14 @@ int i915_vblank_swap(struct drm_device *dev, void *data, | |||
| 618 | 741 | ||
| 619 | if (!vbl_swap) { | 742 | if (!vbl_swap) { |
| 620 | DRM_ERROR("Failed to allocate memory to queue swap\n"); | 743 | DRM_ERROR("Failed to allocate memory to queue swap\n"); |
| 744 | drm_vblank_put(dev, pipe); | ||
| 621 | return -ENOMEM; | 745 | return -ENOMEM; |
| 622 | } | 746 | } |
| 623 | 747 | ||
| 624 | DRM_DEBUG("\n"); | 748 | DRM_DEBUG("\n"); |
| 625 | 749 | ||
| 626 | vbl_swap->drw_id = swap->drawable; | 750 | vbl_swap->drw_id = swap->drawable; |
| 627 | vbl_swap->pipe = pipe; | 751 | vbl_swap->plane = plane; |
| 628 | vbl_swap->sequence = swap->sequence; | 752 | vbl_swap->sequence = swap->sequence; |
| 629 | 753 | ||
| 630 | spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); | 754 | spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); |
| @@ -643,28 +767,32 @@ void i915_driver_irq_preinstall(struct drm_device * dev) | |||
| 643 | { | 767 | { |
| 644 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 768 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
| 645 | 769 | ||
| 646 | I915_WRITE(HWSTAM, 0xfffe); | 770 | I915_WRITE(HWSTAM, 0xeffe); |
| 647 | I915_WRITE(IMR, 0x0); | 771 | I915_WRITE(IMR, 0xffffffff); |
| 648 | I915_WRITE(IER, 0x0); | 772 | I915_WRITE(IER, 0x0); |
| 649 | } | 773 | } |
| 650 | 774 | ||
| 651 | void i915_driver_irq_postinstall(struct drm_device * dev) | 775 | int i915_driver_irq_postinstall(struct drm_device *dev) |
| 652 | { | 776 | { |
| 653 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 777 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
| 778 | int ret, num_pipes = 2; | ||
| 654 | 779 | ||
| 655 | spin_lock_init(&dev_priv->swaps_lock); | 780 | spin_lock_init(&dev_priv->swaps_lock); |
| 656 | INIT_LIST_HEAD(&dev_priv->vbl_swaps.head); | 781 | INIT_LIST_HEAD(&dev_priv->vbl_swaps.head); |
| 657 | dev_priv->swaps_pending = 0; | 782 | dev_priv->swaps_pending = 0; |
| 658 | 783 | ||
| 659 | if (!dev_priv->vblank_pipe) | ||
| 660 | dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A; | ||
| 661 | |||
| 662 | /* Set initial unmasked IRQs to just the selected vblank pipes. */ | 784 | /* Set initial unmasked IRQs to just the selected vblank pipes. */ |
| 663 | dev_priv->irq_mask_reg = ~0; | 785 | dev_priv->irq_mask_reg = ~0; |
| 664 | if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A) | 786 | |
| 665 | dev_priv->irq_mask_reg &= ~I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT; | 787 | ret = drm_vblank_init(dev, num_pipes); |
| 666 | if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B) | 788 | if (ret) |
| 667 | dev_priv->irq_mask_reg &= ~I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; | 789 | return ret; |
| 790 | |||
| 791 | dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; | ||
| 792 | dev_priv->irq_mask_reg &= ~I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT; | ||
| 793 | dev_priv->irq_mask_reg &= ~I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; | ||
| 794 | |||
| 795 | dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ | ||
| 668 | 796 | ||
| 669 | dev_priv->irq_mask_reg &= I915_INTERRUPT_ENABLE_MASK; | 797 | dev_priv->irq_mask_reg &= I915_INTERRUPT_ENABLE_MASK; |
| 670 | 798 | ||
| @@ -673,22 +801,29 @@ void i915_driver_irq_postinstall(struct drm_device * dev) | |||
| 673 | (void) I915_READ(IER); | 801 | (void) I915_READ(IER); |
| 674 | 802 | ||
| 675 | opregion_enable_asle(dev); | 803 | opregion_enable_asle(dev); |
| 676 | |||
| 677 | DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); | 804 | DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); |
| 805 | |||
| 806 | return 0; | ||
| 678 | } | 807 | } |
| 679 | 808 | ||
| 680 | void i915_driver_irq_uninstall(struct drm_device * dev) | 809 | void i915_driver_irq_uninstall(struct drm_device * dev) |
| 681 | { | 810 | { |
| 682 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 811 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
| 683 | u16 temp; | 812 | u32 temp; |
| 684 | 813 | ||
| 685 | if (!dev_priv) | 814 | if (!dev_priv) |
| 686 | return; | 815 | return; |
| 687 | 816 | ||
| 688 | I915_WRITE(HWSTAM, 0xffff); | 817 | dev_priv->vblank_pipe = 0; |
| 689 | I915_WRITE(IMR, 0xffff); | 818 | |
| 819 | I915_WRITE(HWSTAM, 0xffffffff); | ||
| 820 | I915_WRITE(IMR, 0xffffffff); | ||
| 690 | I915_WRITE(IER, 0x0); | 821 | I915_WRITE(IER, 0x0); |
| 691 | 822 | ||
| 823 | temp = I915_READ(PIPEASTAT); | ||
| 824 | I915_WRITE(PIPEASTAT, temp); | ||
| 825 | temp = I915_READ(PIPEBSTAT); | ||
| 826 | I915_WRITE(PIPEBSTAT, temp); | ||
| 692 | temp = I915_READ(IIR); | 827 | temp = I915_READ(IIR); |
| 693 | I915_WRITE(IIR, temp); | 828 | I915_WRITE(IIR, temp); |
| 694 | } | 829 | } |
diff --git a/drivers/gpu/drm/mga/mga_drv.c b/drivers/gpu/drm/mga/mga_drv.c index 5572939fc7d1..97ee566ef749 100644 --- a/drivers/gpu/drm/mga/mga_drv.c +++ b/drivers/gpu/drm/mga/mga_drv.c | |||
| @@ -45,15 +45,16 @@ static struct pci_device_id pciidlist[] = { | |||
| 45 | static struct drm_driver driver = { | 45 | static struct drm_driver driver = { |
| 46 | .driver_features = | 46 | .driver_features = |
| 47 | DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | | 47 | DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | |
| 48 | DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | | 48 | DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED, |
| 49 | DRIVER_IRQ_VBL, | ||
| 50 | .dev_priv_size = sizeof(drm_mga_buf_priv_t), | 49 | .dev_priv_size = sizeof(drm_mga_buf_priv_t), |
| 51 | .load = mga_driver_load, | 50 | .load = mga_driver_load, |
| 52 | .unload = mga_driver_unload, | 51 | .unload = mga_driver_unload, |
| 53 | .lastclose = mga_driver_lastclose, | 52 | .lastclose = mga_driver_lastclose, |
| 54 | .dma_quiescent = mga_driver_dma_quiescent, | 53 | .dma_quiescent = mga_driver_dma_quiescent, |
| 55 | .device_is_agp = mga_driver_device_is_agp, | 54 | .device_is_agp = mga_driver_device_is_agp, |
| 56 | .vblank_wait = mga_driver_vblank_wait, | 55 | .get_vblank_counter = mga_get_vblank_counter, |
| 56 | .enable_vblank = mga_enable_vblank, | ||
| 57 | .disable_vblank = mga_disable_vblank, | ||
| 57 | .irq_preinstall = mga_driver_irq_preinstall, | 58 | .irq_preinstall = mga_driver_irq_preinstall, |
| 58 | .irq_postinstall = mga_driver_irq_postinstall, | 59 | .irq_postinstall = mga_driver_irq_postinstall, |
| 59 | .irq_uninstall = mga_driver_irq_uninstall, | 60 | .irq_uninstall = mga_driver_irq_uninstall, |
| @@ -64,20 +65,20 @@ static struct drm_driver driver = { | |||
| 64 | .ioctls = mga_ioctls, | 65 | .ioctls = mga_ioctls, |
| 65 | .dma_ioctl = mga_dma_buffers, | 66 | .dma_ioctl = mga_dma_buffers, |
| 66 | .fops = { | 67 | .fops = { |
| 67 | .owner = THIS_MODULE, | 68 | .owner = THIS_MODULE, |
| 68 | .open = drm_open, | 69 | .open = drm_open, |
| 69 | .release = drm_release, | 70 | .release = drm_release, |
| 70 | .ioctl = drm_ioctl, | 71 | .ioctl = drm_ioctl, |
| 71 | .mmap = drm_mmap, | 72 | .mmap = drm_mmap, |
| 72 | .poll = drm_poll, | 73 | .poll = drm_poll, |
| 73 | .fasync = drm_fasync, | 74 | .fasync = drm_fasync, |
| 74 | #ifdef CONFIG_COMPAT | 75 | #ifdef CONFIG_COMPAT |
| 75 | .compat_ioctl = mga_compat_ioctl, | 76 | .compat_ioctl = mga_compat_ioctl, |
| 76 | #endif | 77 | #endif |
| 77 | }, | 78 | }, |
| 78 | .pci_driver = { | 79 | .pci_driver = { |
| 79 | .name = DRIVER_NAME, | 80 | .name = DRIVER_NAME, |
| 80 | .id_table = pciidlist, | 81 | .id_table = pciidlist, |
| 81 | }, | 82 | }, |
| 82 | 83 | ||
| 83 | .name = DRIVER_NAME, | 84 | .name = DRIVER_NAME, |
diff --git a/drivers/gpu/drm/mga/mga_drv.h b/drivers/gpu/drm/mga/mga_drv.h index f6ebd24bd587..88257c276eb9 100644 --- a/drivers/gpu/drm/mga/mga_drv.h +++ b/drivers/gpu/drm/mga/mga_drv.h | |||
| @@ -120,6 +120,7 @@ typedef struct drm_mga_private { | |||
| 120 | u32 clear_cmd; | 120 | u32 clear_cmd; |
| 121 | u32 maccess; | 121 | u32 maccess; |
| 122 | 122 | ||
| 123 | atomic_t vbl_received; /**< Number of vblanks received. */ | ||
| 123 | wait_queue_head_t fence_queue; | 124 | wait_queue_head_t fence_queue; |
| 124 | atomic_t last_fence_retired; | 125 | atomic_t last_fence_retired; |
| 125 | u32 next_fence_to_post; | 126 | u32 next_fence_to_post; |
| @@ -181,11 +182,14 @@ extern int mga_warp_install_microcode(drm_mga_private_t * dev_priv); | |||
| 181 | extern int mga_warp_init(drm_mga_private_t * dev_priv); | 182 | extern int mga_warp_init(drm_mga_private_t * dev_priv); |
| 182 | 183 | ||
| 183 | /* mga_irq.c */ | 184 | /* mga_irq.c */ |
| 185 | extern int mga_enable_vblank(struct drm_device *dev, int crtc); | ||
| 186 | extern void mga_disable_vblank(struct drm_device *dev, int crtc); | ||
| 187 | extern u32 mga_get_vblank_counter(struct drm_device *dev, int crtc); | ||
| 184 | extern int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence); | 188 | extern int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence); |
| 185 | extern int mga_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence); | 189 | extern int mga_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence); |
| 186 | extern irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS); | 190 | extern irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS); |
| 187 | extern void mga_driver_irq_preinstall(struct drm_device * dev); | 191 | extern void mga_driver_irq_preinstall(struct drm_device * dev); |
| 188 | extern void mga_driver_irq_postinstall(struct drm_device * dev); | 192 | extern int mga_driver_irq_postinstall(struct drm_device *dev); |
| 189 | extern void mga_driver_irq_uninstall(struct drm_device * dev); | 193 | extern void mga_driver_irq_uninstall(struct drm_device * dev); |
| 190 | extern long mga_compat_ioctl(struct file *filp, unsigned int cmd, | 194 | extern long mga_compat_ioctl(struct file *filp, unsigned int cmd, |
| 191 | unsigned long arg); | 195 | unsigned long arg); |
diff --git a/drivers/gpu/drm/mga/mga_irq.c b/drivers/gpu/drm/mga/mga_irq.c index 9302cb8f0f83..bab42f41188b 100644 --- a/drivers/gpu/drm/mga/mga_irq.c +++ b/drivers/gpu/drm/mga/mga_irq.c | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | /* mga_irq.c -- IRQ handling for radeon -*- linux-c -*- | 1 | /* mga_irq.c -- IRQ handling for radeon -*- linux-c -*- |
| 2 | * | 2 | */ |
| 3 | /* | ||
| 3 | * Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved. | 4 | * Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved. |
| 4 | * | 5 | * |
| 5 | * The Weather Channel (TM) funded Tungsten Graphics to develop the | 6 | * The Weather Channel (TM) funded Tungsten Graphics to develop the |
| @@ -35,6 +36,18 @@ | |||
| 35 | #include "mga_drm.h" | 36 | #include "mga_drm.h" |
| 36 | #include "mga_drv.h" | 37 | #include "mga_drv.h" |
| 37 | 38 | ||
| 39 | u32 mga_get_vblank_counter(struct drm_device *dev, int crtc) | ||
| 40 | { | ||
| 41 | const drm_mga_private_t *const dev_priv = | ||
| 42 | (drm_mga_private_t *) dev->dev_private; | ||
| 43 | |||
| 44 | if (crtc != 0) | ||
| 45 | return 0; | ||
| 46 | |||
| 47 | return atomic_read(&dev_priv->vbl_received); | ||
| 48 | } | ||
| 49 | |||
| 50 | |||
| 38 | irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS) | 51 | irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS) |
| 39 | { | 52 | { |
| 40 | struct drm_device *dev = (struct drm_device *) arg; | 53 | struct drm_device *dev = (struct drm_device *) arg; |
| @@ -47,9 +60,8 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS) | |||
| 47 | /* VBLANK interrupt */ | 60 | /* VBLANK interrupt */ |
| 48 | if (status & MGA_VLINEPEN) { | 61 | if (status & MGA_VLINEPEN) { |
| 49 | MGA_WRITE(MGA_ICLEAR, MGA_VLINEICLR); | 62 | MGA_WRITE(MGA_ICLEAR, MGA_VLINEICLR); |
| 50 | atomic_inc(&dev->vbl_received); | 63 | atomic_inc(&dev_priv->vbl_received); |
| 51 | DRM_WAKEUP(&dev->vbl_queue); | 64 | drm_handle_vblank(dev, 0); |
| 52 | drm_vbl_send_signals(dev); | ||
| 53 | handled = 1; | 65 | handled = 1; |
| 54 | } | 66 | } |
| 55 | 67 | ||
| @@ -58,6 +70,7 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS) | |||
| 58 | const u32 prim_start = MGA_READ(MGA_PRIMADDRESS); | 70 | const u32 prim_start = MGA_READ(MGA_PRIMADDRESS); |
| 59 | const u32 prim_end = MGA_READ(MGA_PRIMEND); | 71 | const u32 prim_end = MGA_READ(MGA_PRIMEND); |
| 60 | 72 | ||
| 73 | |||
| 61 | MGA_WRITE(MGA_ICLEAR, MGA_SOFTRAPICLR); | 74 | MGA_WRITE(MGA_ICLEAR, MGA_SOFTRAPICLR); |
| 62 | 75 | ||
| 63 | /* In addition to clearing the interrupt-pending bit, we | 76 | /* In addition to clearing the interrupt-pending bit, we |
| @@ -72,28 +85,39 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS) | |||
| 72 | handled = 1; | 85 | handled = 1; |
| 73 | } | 86 | } |
| 74 | 87 | ||
| 75 | if (handled) { | 88 | if (handled) |
| 76 | return IRQ_HANDLED; | 89 | return IRQ_HANDLED; |
| 77 | } | ||
| 78 | return IRQ_NONE; | 90 | return IRQ_NONE; |
| 79 | } | 91 | } |
| 80 | 92 | ||
| 81 | int mga_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence) | 93 | int mga_enable_vblank(struct drm_device *dev, int crtc) |
| 82 | { | 94 | { |
| 83 | unsigned int cur_vblank; | 95 | drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; |
| 84 | int ret = 0; | ||
| 85 | 96 | ||
| 86 | /* Assume that the user has missed the current sequence number | 97 | if (crtc != 0) { |
| 87 | * by about a day rather than she wants to wait for years | 98 | DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", |
| 88 | * using vertical blanks... | 99 | crtc); |
| 89 | */ | 100 | return 0; |
| 90 | DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, | 101 | } |
| 91 | (((cur_vblank = atomic_read(&dev->vbl_received)) | ||
| 92 | - *sequence) <= (1 << 23))); | ||
| 93 | 102 | ||
| 94 | *sequence = cur_vblank; | 103 | MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); |
| 104 | return 0; | ||
| 105 | } | ||
| 95 | 106 | ||
| 96 | return ret; | 107 | |
| 108 | void mga_disable_vblank(struct drm_device *dev, int crtc) | ||
| 109 | { | ||
| 110 | if (crtc != 0) { | ||
| 111 | DRM_ERROR("tried to disable vblank on non-existent crtc %d\n", | ||
| 112 | crtc); | ||
| 113 | } | ||
| 114 | |||
| 115 | /* Do *NOT* disable the vertical refresh interrupt. MGA doesn't have | ||
| 116 | * a nice hardware counter that tracks the number of refreshes when | ||
| 117 | * the interrupt is disabled, and the kernel doesn't know the refresh | ||
| 118 | * rate to calculate an estimate. | ||
| 119 | */ | ||
| 120 | /* MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); */ | ||
| 97 | } | 121 | } |
| 98 | 122 | ||
| 99 | int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence) | 123 | int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence) |
| @@ -125,14 +149,22 @@ void mga_driver_irq_preinstall(struct drm_device * dev) | |||
| 125 | MGA_WRITE(MGA_ICLEAR, ~0); | 149 | MGA_WRITE(MGA_ICLEAR, ~0); |
| 126 | } | 150 | } |
| 127 | 151 | ||
| 128 | void mga_driver_irq_postinstall(struct drm_device * dev) | 152 | int mga_driver_irq_postinstall(struct drm_device *dev) |
| 129 | { | 153 | { |
| 130 | drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; | 154 | drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; |
| 155 | int ret; | ||
| 156 | |||
| 157 | ret = drm_vblank_init(dev, 1); | ||
| 158 | if (ret) | ||
| 159 | return ret; | ||
| 131 | 160 | ||
| 132 | DRM_INIT_WAITQUEUE(&dev_priv->fence_queue); | 161 | DRM_INIT_WAITQUEUE(&dev_priv->fence_queue); |
| 133 | 162 | ||
| 134 | /* Turn on vertical blank interrupt and soft trap interrupt. */ | 163 | /* Turn on soft trap interrupt. Vertical blank interrupts are enabled |
| 135 | MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); | 164 | * in mga_enable_vblank. |
| 165 | */ | ||
| 166 | MGA_WRITE(MGA_IEN, MGA_SOFTRAPEN); | ||
| 167 | return 0; | ||
| 136 | } | 168 | } |
| 137 | 169 | ||
| 138 | void mga_driver_irq_uninstall(struct drm_device * dev) | 170 | void mga_driver_irq_uninstall(struct drm_device * dev) |
diff --git a/drivers/gpu/drm/r128/r128_drv.c b/drivers/gpu/drm/r128/r128_drv.c index 6108e7587e12..3265d53ba91f 100644 --- a/drivers/gpu/drm/r128/r128_drv.c +++ b/drivers/gpu/drm/r128/r128_drv.c | |||
| @@ -43,12 +43,13 @@ static struct pci_device_id pciidlist[] = { | |||
| 43 | static struct drm_driver driver = { | 43 | static struct drm_driver driver = { |
| 44 | .driver_features = | 44 | .driver_features = |
| 45 | DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG | | 45 | DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG | |
| 46 | DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | | 46 | DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED, |
| 47 | DRIVER_IRQ_VBL, | ||
| 48 | .dev_priv_size = sizeof(drm_r128_buf_priv_t), | 47 | .dev_priv_size = sizeof(drm_r128_buf_priv_t), |
| 49 | .preclose = r128_driver_preclose, | 48 | .preclose = r128_driver_preclose, |
| 50 | .lastclose = r128_driver_lastclose, | 49 | .lastclose = r128_driver_lastclose, |
| 51 | .vblank_wait = r128_driver_vblank_wait, | 50 | .get_vblank_counter = r128_get_vblank_counter, |
| 51 | .enable_vblank = r128_enable_vblank, | ||
| 52 | .disable_vblank = r128_disable_vblank, | ||
| 52 | .irq_preinstall = r128_driver_irq_preinstall, | 53 | .irq_preinstall = r128_driver_irq_preinstall, |
| 53 | .irq_postinstall = r128_driver_irq_postinstall, | 54 | .irq_postinstall = r128_driver_irq_postinstall, |
| 54 | .irq_uninstall = r128_driver_irq_uninstall, | 55 | .irq_uninstall = r128_driver_irq_uninstall, |
| @@ -59,21 +60,20 @@ static struct drm_driver driver = { | |||
| 59 | .ioctls = r128_ioctls, | 60 | .ioctls = r128_ioctls, |
| 60 | .dma_ioctl = r128_cce_buffers, | 61 | .dma_ioctl = r128_cce_buffers, |
| 61 | .fops = { | 62 | .fops = { |
| 62 | .owner = THIS_MODULE, | 63 | .owner = THIS_MODULE, |
| 63 | .open = drm_open, | 64 | .open = drm_open, |
| 64 | .release = drm_release, | 65 | .release = drm_release, |
| 65 | .ioctl = drm_ioctl, | 66 | .ioctl = drm_ioctl, |
| 66 | .mmap = drm_mmap, | 67 | .mmap = drm_mmap, |
| 67 | .poll = drm_poll, | 68 | .poll = drm_poll, |
| 68 | .fasync = drm_fasync, | 69 | .fasync = drm_fasync, |
| 69 | #ifdef CONFIG_COMPAT | 70 | #ifdef CONFIG_COMPAT |
| 70 | .compat_ioctl = r128_compat_ioctl, | 71 | .compat_ioctl = r128_compat_ioctl, |
| 71 | #endif | 72 | #endif |
| 72 | }, | 73 | }, |
| 73 | |||
| 74 | .pci_driver = { | 74 | .pci_driver = { |
| 75 | .name = DRIVER_NAME, | 75 | .name = DRIVER_NAME, |
| 76 | .id_table = pciidlist, | 76 | .id_table = pciidlist, |
| 77 | }, | 77 | }, |
| 78 | 78 | ||
| 79 | .name = DRIVER_NAME, | 79 | .name = DRIVER_NAME, |
| @@ -87,6 +87,7 @@ static struct drm_driver driver = { | |||
| 87 | static int __init r128_init(void) | 87 | static int __init r128_init(void) |
| 88 | { | 88 | { |
| 89 | driver.num_ioctls = r128_max_ioctl; | 89 | driver.num_ioctls = r128_max_ioctl; |
| 90 | |||
| 90 | return drm_init(&driver); | 91 | return drm_init(&driver); |
| 91 | } | 92 | } |
| 92 | 93 | ||
diff --git a/drivers/gpu/drm/r128/r128_drv.h b/drivers/gpu/drm/r128/r128_drv.h index 011105e51ac6..5898b274279d 100644 --- a/drivers/gpu/drm/r128/r128_drv.h +++ b/drivers/gpu/drm/r128/r128_drv.h | |||
| @@ -29,7 +29,7 @@ | |||
| 29 | * Rickard E. (Rik) Faith <faith@valinux.com> | 29 | * Rickard E. (Rik) Faith <faith@valinux.com> |
| 30 | * Kevin E. Martin <martin@valinux.com> | 30 | * Kevin E. Martin <martin@valinux.com> |
| 31 | * Gareth Hughes <gareth@valinux.com> | 31 | * Gareth Hughes <gareth@valinux.com> |
| 32 | * Michel Dänzer <daenzerm@student.ethz.ch> | 32 | * Michel D�zer <daenzerm@student.ethz.ch> |
| 33 | */ | 33 | */ |
| 34 | 34 | ||
| 35 | #ifndef __R128_DRV_H__ | 35 | #ifndef __R128_DRV_H__ |
| @@ -97,6 +97,8 @@ typedef struct drm_r128_private { | |||
| 97 | u32 crtc_offset; | 97 | u32 crtc_offset; |
| 98 | u32 crtc_offset_cntl; | 98 | u32 crtc_offset_cntl; |
| 99 | 99 | ||
| 100 | atomic_t vbl_received; | ||
| 101 | |||
| 100 | u32 color_fmt; | 102 | u32 color_fmt; |
| 101 | unsigned int front_offset; | 103 | unsigned int front_offset; |
| 102 | unsigned int front_pitch; | 104 | unsigned int front_pitch; |
| @@ -149,11 +151,12 @@ extern int r128_wait_ring(drm_r128_private_t * dev_priv, int n); | |||
| 149 | extern int r128_do_cce_idle(drm_r128_private_t * dev_priv); | 151 | extern int r128_do_cce_idle(drm_r128_private_t * dev_priv); |
| 150 | extern int r128_do_cleanup_cce(struct drm_device * dev); | 152 | extern int r128_do_cleanup_cce(struct drm_device * dev); |
| 151 | 153 | ||
| 152 | extern int r128_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence); | 154 | extern int r128_enable_vblank(struct drm_device *dev, int crtc); |
| 153 | 155 | extern void r128_disable_vblank(struct drm_device *dev, int crtc); | |
| 156 | extern u32 r128_get_vblank_counter(struct drm_device *dev, int crtc); | ||
| 154 | extern irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS); | 157 | extern irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS); |
| 155 | extern void r128_driver_irq_preinstall(struct drm_device * dev); | 158 | extern void r128_driver_irq_preinstall(struct drm_device * dev); |
| 156 | extern void r128_driver_irq_postinstall(struct drm_device * dev); | 159 | extern int r128_driver_irq_postinstall(struct drm_device *dev); |
| 157 | extern void r128_driver_irq_uninstall(struct drm_device * dev); | 160 | extern void r128_driver_irq_uninstall(struct drm_device * dev); |
| 158 | extern void r128_driver_lastclose(struct drm_device * dev); | 161 | extern void r128_driver_lastclose(struct drm_device * dev); |
| 159 | extern void r128_driver_preclose(struct drm_device * dev, | 162 | extern void r128_driver_preclose(struct drm_device * dev, |
diff --git a/drivers/gpu/drm/r128/r128_irq.c b/drivers/gpu/drm/r128/r128_irq.c index c76fdca7662d..d7349012a680 100644 --- a/drivers/gpu/drm/r128/r128_irq.c +++ b/drivers/gpu/drm/r128/r128_irq.c | |||
| @@ -35,6 +35,16 @@ | |||
| 35 | #include "r128_drm.h" | 35 | #include "r128_drm.h" |
| 36 | #include "r128_drv.h" | 36 | #include "r128_drv.h" |
| 37 | 37 | ||
| 38 | u32 r128_get_vblank_counter(struct drm_device *dev, int crtc) | ||
| 39 | { | ||
| 40 | const drm_r128_private_t *dev_priv = dev->dev_private; | ||
| 41 | |||
| 42 | if (crtc != 0) | ||
| 43 | return 0; | ||
| 44 | |||
| 45 | return atomic_read(&dev_priv->vbl_received); | ||
| 46 | } | ||
| 47 | |||
| 38 | irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS) | 48 | irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS) |
| 39 | { | 49 | { |
| 40 | struct drm_device *dev = (struct drm_device *) arg; | 50 | struct drm_device *dev = (struct drm_device *) arg; |
| @@ -46,30 +56,38 @@ irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS) | |||
| 46 | /* VBLANK interrupt */ | 56 | /* VBLANK interrupt */ |
| 47 | if (status & R128_CRTC_VBLANK_INT) { | 57 | if (status & R128_CRTC_VBLANK_INT) { |
| 48 | R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK); | 58 | R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK); |
| 49 | atomic_inc(&dev->vbl_received); | 59 | atomic_inc(&dev_priv->vbl_received); |
| 50 | DRM_WAKEUP(&dev->vbl_queue); | 60 | drm_handle_vblank(dev, 0); |
| 51 | drm_vbl_send_signals(dev); | ||
| 52 | return IRQ_HANDLED; | 61 | return IRQ_HANDLED; |
| 53 | } | 62 | } |
| 54 | return IRQ_NONE; | 63 | return IRQ_NONE; |
| 55 | } | 64 | } |
| 56 | 65 | ||
| 57 | int r128_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence) | 66 | int r128_enable_vblank(struct drm_device *dev, int crtc) |
| 58 | { | 67 | { |
| 59 | unsigned int cur_vblank; | 68 | drm_r128_private_t *dev_priv = dev->dev_private; |
| 60 | int ret = 0; | ||
| 61 | 69 | ||
| 62 | /* Assume that the user has missed the current sequence number | 70 | if (crtc != 0) { |
| 63 | * by about a day rather than she wants to wait for years | 71 | DRM_ERROR("%s: bad crtc %d\n", __func__, crtc); |
| 64 | * using vertical blanks... | 72 | return -EINVAL; |
| 65 | */ | 73 | } |
| 66 | DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, | ||
| 67 | (((cur_vblank = atomic_read(&dev->vbl_received)) | ||
| 68 | - *sequence) <= (1 << 23))); | ||
| 69 | 74 | ||
| 70 | *sequence = cur_vblank; | 75 | R128_WRITE(R128_GEN_INT_CNTL, R128_CRTC_VBLANK_INT_EN); |
| 76 | return 0; | ||
| 77 | } | ||
| 78 | |||
| 79 | void r128_disable_vblank(struct drm_device *dev, int crtc) | ||
| 80 | { | ||
| 81 | if (crtc != 0) | ||
| 82 | DRM_ERROR("%s: bad crtc %d\n", __func__, crtc); | ||
| 71 | 83 | ||
| 72 | return ret; | 84 | /* |
| 85 | * FIXME: implement proper interrupt disable by using the vblank | ||
| 86 | * counter register (if available) | ||
| 87 | * | ||
| 88 | * R128_WRITE(R128_GEN_INT_CNTL, | ||
| 89 | * R128_READ(R128_GEN_INT_CNTL) & ~R128_CRTC_VBLANK_INT_EN); | ||
| 90 | */ | ||
| 73 | } | 91 | } |
| 74 | 92 | ||
| 75 | void r128_driver_irq_preinstall(struct drm_device * dev) | 93 | void r128_driver_irq_preinstall(struct drm_device * dev) |
| @@ -82,12 +100,9 @@ void r128_driver_irq_preinstall(struct drm_device * dev) | |||
| 82 | R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK); | 100 | R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK); |
| 83 | } | 101 | } |
| 84 | 102 | ||
| 85 | void r128_driver_irq_postinstall(struct drm_device * dev) | 103 | int r128_driver_irq_postinstall(struct drm_device *dev) |
| 86 | { | 104 | { |
| 87 | drm_r128_private_t *dev_priv = (drm_r128_private_t *) dev->dev_private; | 105 | return drm_vblank_init(dev, 1); |
| 88 | |||
| 89 | /* Turn on VBL interrupt */ | ||
| 90 | R128_WRITE(R128_GEN_INT_CNTL, R128_CRTC_VBLANK_INT_EN); | ||
| 91 | } | 106 | } |
| 92 | 107 | ||
| 93 | void r128_driver_irq_uninstall(struct drm_device * dev) | 108 | void r128_driver_irq_uninstall(struct drm_device * dev) |
diff --git a/drivers/gpu/drm/radeon/radeon_cp.c b/drivers/gpu/drm/radeon/radeon_cp.c index e1678cae9ccb..6157cd4bb436 100644 --- a/drivers/gpu/drm/radeon/radeon_cp.c +++ b/drivers/gpu/drm/radeon/radeon_cp.c | |||
| @@ -1287,7 +1287,7 @@ static int radeon_do_resume_cp(struct drm_device * dev) | |||
| 1287 | radeon_cp_init_ring_buffer(dev, dev_priv); | 1287 | radeon_cp_init_ring_buffer(dev, dev_priv); |
| 1288 | 1288 | ||
| 1289 | radeon_do_engine_reset(dev); | 1289 | radeon_do_engine_reset(dev); |
| 1290 | radeon_enable_interrupt(dev); | 1290 | radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1); |
| 1291 | 1291 | ||
| 1292 | DRM_DEBUG("radeon_do_resume_cp() complete\n"); | 1292 | DRM_DEBUG("radeon_do_resume_cp() complete\n"); |
| 1293 | 1293 | ||
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 637bd7faf132..71af746a4e47 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c | |||
| @@ -52,6 +52,28 @@ static int dri_library_name(struct drm_device *dev, char *buf) | |||
| 52 | "r300")); | 52 | "r300")); |
| 53 | } | 53 | } |
| 54 | 54 | ||
| 55 | static int radeon_suspend(struct drm_device *dev, pm_message_t state) | ||
| 56 | { | ||
| 57 | drm_radeon_private_t *dev_priv = dev->dev_private; | ||
| 58 | |||
| 59 | /* Disable *all* interrupts */ | ||
| 60 | if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) | ||
| 61 | RADEON_WRITE(R500_DxMODE_INT_MASK, 0); | ||
| 62 | RADEON_WRITE(RADEON_GEN_INT_CNTL, 0); | ||
| 63 | return 0; | ||
| 64 | } | ||
| 65 | |||
| 66 | static int radeon_resume(struct drm_device *dev) | ||
| 67 | { | ||
| 68 | drm_radeon_private_t *dev_priv = dev->dev_private; | ||
| 69 | |||
| 70 | /* Restore interrupt registers */ | ||
| 71 | if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) | ||
| 72 | RADEON_WRITE(R500_DxMODE_INT_MASK, dev_priv->r500_disp_irq_reg); | ||
| 73 | RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg); | ||
| 74 | return 0; | ||
| 75 | } | ||
| 76 | |||
| 55 | static struct pci_device_id pciidlist[] = { | 77 | static struct pci_device_id pciidlist[] = { |
| 56 | radeon_PCI_IDS | 78 | radeon_PCI_IDS |
| 57 | }; | 79 | }; |
| @@ -59,8 +81,7 @@ static struct pci_device_id pciidlist[] = { | |||
| 59 | static struct drm_driver driver = { | 81 | static struct drm_driver driver = { |
| 60 | .driver_features = | 82 | .driver_features = |
| 61 | DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG | | 83 | DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG | |
| 62 | DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED | | 84 | DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED, |
| 63 | DRIVER_IRQ_VBL | DRIVER_IRQ_VBL2, | ||
| 64 | .dev_priv_size = sizeof(drm_radeon_buf_priv_t), | 85 | .dev_priv_size = sizeof(drm_radeon_buf_priv_t), |
| 65 | .load = radeon_driver_load, | 86 | .load = radeon_driver_load, |
| 66 | .firstopen = radeon_driver_firstopen, | 87 | .firstopen = radeon_driver_firstopen, |
| @@ -69,8 +90,11 @@ static struct drm_driver driver = { | |||
| 69 | .postclose = radeon_driver_postclose, | 90 | .postclose = radeon_driver_postclose, |
| 70 | .lastclose = radeon_driver_lastclose, | 91 | .lastclose = radeon_driver_lastclose, |
| 71 | .unload = radeon_driver_unload, | 92 | .unload = radeon_driver_unload, |
| 72 | .vblank_wait = radeon_driver_vblank_wait, | 93 | .suspend = radeon_suspend, |
| 73 | .vblank_wait2 = radeon_driver_vblank_wait2, | 94 | .resume = radeon_resume, |
| 95 | .get_vblank_counter = radeon_get_vblank_counter, | ||
| 96 | .enable_vblank = radeon_enable_vblank, | ||
| 97 | .disable_vblank = radeon_disable_vblank, | ||
| 74 | .dri_library_name = dri_library_name, | 98 | .dri_library_name = dri_library_name, |
| 75 | .irq_preinstall = radeon_driver_irq_preinstall, | 99 | .irq_preinstall = radeon_driver_irq_preinstall, |
| 76 | .irq_postinstall = radeon_driver_irq_postinstall, | 100 | .irq_postinstall = radeon_driver_irq_postinstall, |
diff --git a/drivers/gpu/drm/radeon/radeon_drv.h b/drivers/gpu/drm/radeon/radeon_drv.h index 099381693175..d7e9c6cc6a1a 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.h +++ b/drivers/gpu/drm/radeon/radeon_drv.h | |||
| @@ -378,17 +378,17 @@ extern void radeon_mem_release(struct drm_file *file_priv, | |||
| 378 | struct mem_block *heap); | 378 | struct mem_block *heap); |
| 379 | 379 | ||
| 380 | /* radeon_irq.c */ | 380 | /* radeon_irq.c */ |
| 381 | extern void radeon_irq_set_state(struct drm_device *dev, u32 mask, int state); | ||
| 381 | extern int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv); | 382 | extern int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv); |
| 382 | extern int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv); | 383 | extern int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv); |
| 383 | 384 | ||
| 384 | extern void radeon_do_release(struct drm_device * dev); | 385 | extern void radeon_do_release(struct drm_device * dev); |
| 385 | extern int radeon_driver_vblank_wait(struct drm_device * dev, | 386 | extern u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc); |
| 386 | unsigned int *sequence); | 387 | extern int radeon_enable_vblank(struct drm_device *dev, int crtc); |
| 387 | extern int radeon_driver_vblank_wait2(struct drm_device * dev, | 388 | extern void radeon_disable_vblank(struct drm_device *dev, int crtc); |
| 388 | unsigned int *sequence); | ||
| 389 | extern irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS); | 389 | extern irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS); |
| 390 | extern void radeon_driver_irq_preinstall(struct drm_device * dev); | 390 | extern void radeon_driver_irq_preinstall(struct drm_device * dev); |
| 391 | extern void radeon_driver_irq_postinstall(struct drm_device * dev); | 391 | extern int radeon_driver_irq_postinstall(struct drm_device *dev); |
| 392 | extern void radeon_driver_irq_uninstall(struct drm_device * dev); | 392 | extern void radeon_driver_irq_uninstall(struct drm_device * dev); |
| 393 | extern void radeon_enable_interrupt(struct drm_device *dev); | 393 | extern void radeon_enable_interrupt(struct drm_device *dev); |
| 394 | extern int radeon_vblank_crtc_get(struct drm_device *dev); | 394 | extern int radeon_vblank_crtc_get(struct drm_device *dev); |
| @@ -397,19 +397,22 @@ extern int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value); | |||
| 397 | extern int radeon_driver_load(struct drm_device *dev, unsigned long flags); | 397 | extern int radeon_driver_load(struct drm_device *dev, unsigned long flags); |
| 398 | extern int radeon_driver_unload(struct drm_device *dev); | 398 | extern int radeon_driver_unload(struct drm_device *dev); |
| 399 | extern int radeon_driver_firstopen(struct drm_device *dev); | 399 | extern int radeon_driver_firstopen(struct drm_device *dev); |
| 400 | extern void radeon_driver_preclose(struct drm_device * dev, struct drm_file *file_priv); | 400 | extern void radeon_driver_preclose(struct drm_device *dev, |
| 401 | extern void radeon_driver_postclose(struct drm_device * dev, struct drm_file * filp); | 401 | struct drm_file *file_priv); |
| 402 | extern void radeon_driver_postclose(struct drm_device *dev, | ||
| 403 | struct drm_file *file_priv); | ||
| 402 | extern void radeon_driver_lastclose(struct drm_device * dev); | 404 | extern void radeon_driver_lastclose(struct drm_device * dev); |
| 403 | extern int radeon_driver_open(struct drm_device * dev, struct drm_file * filp_priv); | 405 | extern int radeon_driver_open(struct drm_device *dev, |
| 406 | struct drm_file *file_priv); | ||
| 404 | extern long radeon_compat_ioctl(struct file *filp, unsigned int cmd, | 407 | extern long radeon_compat_ioctl(struct file *filp, unsigned int cmd, |
| 405 | unsigned long arg); | 408 | unsigned long arg); |
| 406 | 409 | ||
| 407 | /* r300_cmdbuf.c */ | 410 | /* r300_cmdbuf.c */ |
| 408 | extern void r300_init_reg_flags(struct drm_device *dev); | 411 | extern void r300_init_reg_flags(struct drm_device *dev); |
| 409 | 412 | ||
| 410 | extern int r300_do_cp_cmdbuf(struct drm_device * dev, | 413 | extern int r300_do_cp_cmdbuf(struct drm_device *dev, |
| 411 | struct drm_file *file_priv, | 414 | struct drm_file *file_priv, |
| 412 | drm_radeon_kcmd_buffer_t * cmdbuf); | 415 | drm_radeon_kcmd_buffer_t *cmdbuf); |
| 413 | 416 | ||
| 414 | /* Flags for stats.boxes | 417 | /* Flags for stats.boxes |
| 415 | */ | 418 | */ |
| @@ -623,6 +626,7 @@ extern int r300_do_cp_cmdbuf(struct drm_device * dev, | |||
| 623 | # define RADEON_SW_INT_TEST (1 << 25) | 626 | # define RADEON_SW_INT_TEST (1 << 25) |
| 624 | # define RADEON_SW_INT_TEST_ACK (1 << 25) | 627 | # define RADEON_SW_INT_TEST_ACK (1 << 25) |
| 625 | # define RADEON_SW_INT_FIRE (1 << 26) | 628 | # define RADEON_SW_INT_FIRE (1 << 26) |
| 629 | # define R500_DISPLAY_INT_STATUS (1 << 0) | ||
| 626 | 630 | ||
| 627 | #define RADEON_HOST_PATH_CNTL 0x0130 | 631 | #define RADEON_HOST_PATH_CNTL 0x0130 |
| 628 | # define RADEON_HDP_SOFT_RESET (1 << 26) | 632 | # define RADEON_HDP_SOFT_RESET (1 << 26) |
| @@ -1116,6 +1120,9 @@ extern int r300_do_cp_cmdbuf(struct drm_device * dev, | |||
| 1116 | 1120 | ||
| 1117 | #define R200_VAP_PVS_CNTL_1 0x22D0 | 1121 | #define R200_VAP_PVS_CNTL_1 0x22D0 |
| 1118 | 1122 | ||
| 1123 | #define RADEON_CRTC_CRNT_FRAME 0x0214 | ||
| 1124 | #define RADEON_CRTC2_CRNT_FRAME 0x0314 | ||
| 1125 | |||
| 1119 | #define R500_D1CRTC_STATUS 0x609c | 1126 | #define R500_D1CRTC_STATUS 0x609c |
| 1120 | #define R500_D2CRTC_STATUS 0x689c | 1127 | #define R500_D2CRTC_STATUS 0x689c |
| 1121 | #define R500_CRTC_V_BLANK (1<<0) | 1128 | #define R500_CRTC_V_BLANK (1<<0) |
diff --git a/drivers/gpu/drm/radeon/radeon_irq.c b/drivers/gpu/drm/radeon/radeon_irq.c index ee40d197deb7..5079f7054a2f 100644 --- a/drivers/gpu/drm/radeon/radeon_irq.c +++ b/drivers/gpu/drm/radeon/radeon_irq.c | |||
| @@ -27,7 +27,7 @@ | |||
| 27 | * | 27 | * |
| 28 | * Authors: | 28 | * Authors: |
| 29 | * Keith Whitwell <keith@tungstengraphics.com> | 29 | * Keith Whitwell <keith@tungstengraphics.com> |
| 30 | * Michel Dänzer <michel@daenzer.net> | 30 | * Michel D�zer <michel@daenzer.net> |
| 31 | */ | 31 | */ |
| 32 | 32 | ||
| 33 | #include "drmP.h" | 33 | #include "drmP.h" |
| @@ -35,12 +35,128 @@ | |||
| 35 | #include "radeon_drm.h" | 35 | #include "radeon_drm.h" |
| 36 | #include "radeon_drv.h" | 36 | #include "radeon_drv.h" |
| 37 | 37 | ||
| 38 | static __inline__ u32 radeon_acknowledge_irqs(drm_radeon_private_t * dev_priv, | 38 | void radeon_irq_set_state(struct drm_device *dev, u32 mask, int state) |
| 39 | u32 mask) | ||
| 40 | { | 39 | { |
| 41 | u32 irqs = RADEON_READ(RADEON_GEN_INT_STATUS) & mask; | 40 | drm_radeon_private_t *dev_priv = dev->dev_private; |
| 41 | |||
| 42 | if (state) | ||
| 43 | dev_priv->irq_enable_reg |= mask; | ||
| 44 | else | ||
| 45 | dev_priv->irq_enable_reg &= ~mask; | ||
| 46 | |||
| 47 | RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg); | ||
| 48 | } | ||
| 49 | |||
| 50 | static void r500_vbl_irq_set_state(struct drm_device *dev, u32 mask, int state) | ||
| 51 | { | ||
| 52 | drm_radeon_private_t *dev_priv = dev->dev_private; | ||
| 53 | |||
| 54 | if (state) | ||
| 55 | dev_priv->r500_disp_irq_reg |= mask; | ||
| 56 | else | ||
| 57 | dev_priv->r500_disp_irq_reg &= ~mask; | ||
| 58 | |||
| 59 | RADEON_WRITE(R500_DxMODE_INT_MASK, dev_priv->r500_disp_irq_reg); | ||
| 60 | } | ||
| 61 | |||
| 62 | int radeon_enable_vblank(struct drm_device *dev, int crtc) | ||
| 63 | { | ||
| 64 | drm_radeon_private_t *dev_priv = dev->dev_private; | ||
| 65 | |||
| 66 | if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) { | ||
| 67 | switch (crtc) { | ||
| 68 | case 0: | ||
| 69 | r500_vbl_irq_set_state(dev, R500_D1MODE_INT_MASK, 1); | ||
| 70 | break; | ||
| 71 | case 1: | ||
| 72 | r500_vbl_irq_set_state(dev, R500_D2MODE_INT_MASK, 1); | ||
| 73 | break; | ||
| 74 | default: | ||
| 75 | DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", | ||
| 76 | crtc); | ||
| 77 | return EINVAL; | ||
| 78 | } | ||
| 79 | } else { | ||
| 80 | switch (crtc) { | ||
| 81 | case 0: | ||
| 82 | radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 1); | ||
| 83 | break; | ||
| 84 | case 1: | ||
| 85 | radeon_irq_set_state(dev, RADEON_CRTC2_VBLANK_MASK, 1); | ||
| 86 | break; | ||
| 87 | default: | ||
| 88 | DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", | ||
| 89 | crtc); | ||
| 90 | return EINVAL; | ||
| 91 | } | ||
| 92 | } | ||
| 93 | |||
| 94 | return 0; | ||
| 95 | } | ||
| 96 | |||
| 97 | void radeon_disable_vblank(struct drm_device *dev, int crtc) | ||
| 98 | { | ||
| 99 | drm_radeon_private_t *dev_priv = dev->dev_private; | ||
| 100 | |||
| 101 | if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) { | ||
| 102 | switch (crtc) { | ||
| 103 | case 0: | ||
| 104 | r500_vbl_irq_set_state(dev, R500_D1MODE_INT_MASK, 0); | ||
| 105 | break; | ||
| 106 | case 1: | ||
| 107 | r500_vbl_irq_set_state(dev, R500_D2MODE_INT_MASK, 0); | ||
| 108 | break; | ||
| 109 | default: | ||
| 110 | DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", | ||
| 111 | crtc); | ||
| 112 | break; | ||
| 113 | } | ||
| 114 | } else { | ||
| 115 | switch (crtc) { | ||
| 116 | case 0: | ||
| 117 | radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 0); | ||
| 118 | break; | ||
| 119 | case 1: | ||
| 120 | radeon_irq_set_state(dev, RADEON_CRTC2_VBLANK_MASK, 0); | ||
| 121 | break; | ||
| 122 | default: | ||
| 123 | DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", | ||
| 124 | crtc); | ||
| 125 | break; | ||
| 126 | } | ||
| 127 | } | ||
| 128 | } | ||
| 129 | |||
| 130 | static inline u32 radeon_acknowledge_irqs(drm_radeon_private_t *dev_priv, u32 *r500_disp_int) | ||
| 131 | { | ||
| 132 | u32 irqs = RADEON_READ(RADEON_GEN_INT_STATUS); | ||
| 133 | u32 irq_mask = RADEON_SW_INT_TEST; | ||
| 134 | |||
| 135 | *r500_disp_int = 0; | ||
| 136 | if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) { | ||
| 137 | /* vbl interrupts in a different place */ | ||
| 138 | |||
| 139 | if (irqs & R500_DISPLAY_INT_STATUS) { | ||
| 140 | /* if a display interrupt */ | ||
| 141 | u32 disp_irq; | ||
| 142 | |||
| 143 | disp_irq = RADEON_READ(R500_DISP_INTERRUPT_STATUS); | ||
| 144 | |||
| 145 | *r500_disp_int = disp_irq; | ||
| 146 | if (disp_irq & R500_D1_VBLANK_INTERRUPT) | ||
| 147 | RADEON_WRITE(R500_D1MODE_VBLANK_STATUS, R500_VBLANK_ACK); | ||
| 148 | if (disp_irq & R500_D2_VBLANK_INTERRUPT) | ||
| 149 | RADEON_WRITE(R500_D2MODE_VBLANK_STATUS, R500_VBLANK_ACK); | ||
| 150 | } | ||
| 151 | irq_mask |= R500_DISPLAY_INT_STATUS; | ||
| 152 | } else | ||
| 153 | irq_mask |= RADEON_CRTC_VBLANK_STAT | RADEON_CRTC2_VBLANK_STAT; | ||
| 154 | |||
| 155 | irqs &= irq_mask; | ||
| 156 | |||
| 42 | if (irqs) | 157 | if (irqs) |
| 43 | RADEON_WRITE(RADEON_GEN_INT_STATUS, irqs); | 158 | RADEON_WRITE(RADEON_GEN_INT_STATUS, irqs); |
| 159 | |||
| 44 | return irqs; | 160 | return irqs; |
| 45 | } | 161 | } |
| 46 | 162 | ||
| @@ -68,44 +184,33 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS) | |||
| 68 | drm_radeon_private_t *dev_priv = | 184 | drm_radeon_private_t *dev_priv = |
| 69 | (drm_radeon_private_t *) dev->dev_private; | 185 | (drm_radeon_private_t *) dev->dev_private; |
| 70 | u32 stat; | 186 | u32 stat; |
| 187 | u32 r500_disp_int; | ||
| 71 | 188 | ||
| 72 | /* Only consider the bits we're interested in - others could be used | 189 | /* Only consider the bits we're interested in - others could be used |
| 73 | * outside the DRM | 190 | * outside the DRM |
| 74 | */ | 191 | */ |
| 75 | stat = radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK | | 192 | stat = radeon_acknowledge_irqs(dev_priv, &r500_disp_int); |
| 76 | RADEON_CRTC_VBLANK_STAT | | ||
| 77 | RADEON_CRTC2_VBLANK_STAT)); | ||
| 78 | if (!stat) | 193 | if (!stat) |
| 79 | return IRQ_NONE; | 194 | return IRQ_NONE; |
| 80 | 195 | ||
| 81 | stat &= dev_priv->irq_enable_reg; | 196 | stat &= dev_priv->irq_enable_reg; |
| 82 | 197 | ||
| 83 | /* SW interrupt */ | 198 | /* SW interrupt */ |
| 84 | if (stat & RADEON_SW_INT_TEST) { | 199 | if (stat & RADEON_SW_INT_TEST) |
| 85 | DRM_WAKEUP(&dev_priv->swi_queue); | 200 | DRM_WAKEUP(&dev_priv->swi_queue); |
| 86 | } | ||
| 87 | 201 | ||
| 88 | /* VBLANK interrupt */ | 202 | /* VBLANK interrupt */ |
| 89 | if (stat & (RADEON_CRTC_VBLANK_STAT|RADEON_CRTC2_VBLANK_STAT)) { | 203 | if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) { |
| 90 | int vblank_crtc = dev_priv->vblank_crtc; | 204 | if (r500_disp_int & R500_D1_VBLANK_INTERRUPT) |
| 91 | 205 | drm_handle_vblank(dev, 0); | |
| 92 | if ((vblank_crtc & | 206 | if (r500_disp_int & R500_D2_VBLANK_INTERRUPT) |
| 93 | (DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2)) == | 207 | drm_handle_vblank(dev, 1); |
| 94 | (DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2)) { | 208 | } else { |
| 95 | if (stat & RADEON_CRTC_VBLANK_STAT) | 209 | if (stat & RADEON_CRTC_VBLANK_STAT) |
| 96 | atomic_inc(&dev->vbl_received); | 210 | drm_handle_vblank(dev, 0); |
| 97 | if (stat & RADEON_CRTC2_VBLANK_STAT) | 211 | if (stat & RADEON_CRTC2_VBLANK_STAT) |
| 98 | atomic_inc(&dev->vbl_received2); | 212 | drm_handle_vblank(dev, 1); |
| 99 | } else if (((stat & RADEON_CRTC_VBLANK_STAT) && | ||
| 100 | (vblank_crtc & DRM_RADEON_VBLANK_CRTC1)) || | ||
| 101 | ((stat & RADEON_CRTC2_VBLANK_STAT) && | ||
| 102 | (vblank_crtc & DRM_RADEON_VBLANK_CRTC2))) | ||
| 103 | atomic_inc(&dev->vbl_received); | ||
| 104 | |||
| 105 | DRM_WAKEUP(&dev->vbl_queue); | ||
| 106 | drm_vbl_send_signals(dev); | ||
| 107 | } | 213 | } |
| 108 | |||
| 109 | return IRQ_HANDLED; | 214 | return IRQ_HANDLED; |
| 110 | } | 215 | } |
| 111 | 216 | ||
| @@ -144,54 +249,31 @@ static int radeon_wait_irq(struct drm_device * dev, int swi_nr) | |||
| 144 | return ret; | 249 | return ret; |
| 145 | } | 250 | } |
| 146 | 251 | ||
| 147 | static int radeon_driver_vblank_do_wait(struct drm_device * dev, | 252 | u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc) |
| 148 | unsigned int *sequence, int crtc) | ||
| 149 | { | 253 | { |
| 150 | drm_radeon_private_t *dev_priv = | 254 | drm_radeon_private_t *dev_priv = dev->dev_private; |
| 151 | (drm_radeon_private_t *) dev->dev_private; | 255 | |
| 152 | unsigned int cur_vblank; | ||
| 153 | int ret = 0; | ||
| 154 | int ack = 0; | ||
| 155 | atomic_t *counter; | ||
| 156 | if (!dev_priv) { | 256 | if (!dev_priv) { |
| 157 | DRM_ERROR("called with no initialization\n"); | 257 | DRM_ERROR("called with no initialization\n"); |
| 158 | return -EINVAL; | 258 | return -EINVAL; |
| 159 | } | 259 | } |
| 160 | 260 | ||
| 161 | if (crtc == DRM_RADEON_VBLANK_CRTC1) { | 261 | if (crtc < 0 || crtc > 1) { |
| 162 | counter = &dev->vbl_received; | 262 | DRM_ERROR("Invalid crtc %d\n", crtc); |
| 163 | ack |= RADEON_CRTC_VBLANK_STAT; | ||
| 164 | } else if (crtc == DRM_RADEON_VBLANK_CRTC2) { | ||
| 165 | counter = &dev->vbl_received2; | ||
| 166 | ack |= RADEON_CRTC2_VBLANK_STAT; | ||
| 167 | } else | ||
| 168 | return -EINVAL; | 263 | return -EINVAL; |
| 264 | } | ||
| 169 | 265 | ||
| 170 | radeon_acknowledge_irqs(dev_priv, ack); | 266 | if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) { |
| 171 | 267 | if (crtc == 0) | |
| 172 | dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE; | 268 | return RADEON_READ(R500_D1CRTC_FRAME_COUNT); |
| 173 | 269 | else | |
| 174 | /* Assume that the user has missed the current sequence number | 270 | return RADEON_READ(R500_D2CRTC_FRAME_COUNT); |
| 175 | * by about a day rather than she wants to wait for years | 271 | } else { |
| 176 | * using vertical blanks... | 272 | if (crtc == 0) |
| 177 | */ | 273 | return RADEON_READ(RADEON_CRTC_CRNT_FRAME); |
| 178 | DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, | 274 | else |
| 179 | (((cur_vblank = atomic_read(counter)) | 275 | return RADEON_READ(RADEON_CRTC2_CRNT_FRAME); |
| 180 | - *sequence) <= (1 << 23))); | 276 | } |
| 181 | |||
| 182 | *sequence = cur_vblank; | ||
| 183 | |||
| 184 | return ret; | ||
| 185 | } | ||
| 186 | |||
| 187 | int radeon_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence) | ||
| 188 | { | ||
| 189 | return radeon_driver_vblank_do_wait(dev, sequence, DRM_RADEON_VBLANK_CRTC1); | ||
| 190 | } | ||
| 191 | |||
| 192 | int radeon_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence) | ||
| 193 | { | ||
| 194 | return radeon_driver_vblank_do_wait(dev, sequence, DRM_RADEON_VBLANK_CRTC2); | ||
| 195 | } | 277 | } |
| 196 | 278 | ||
| 197 | /* Needs the lock as it touches the ring. | 279 | /* Needs the lock as it touches the ring. |
| @@ -234,46 +316,41 @@ int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_pr | |||
| 234 | return radeon_wait_irq(dev, irqwait->irq_seq); | 316 | return radeon_wait_irq(dev, irqwait->irq_seq); |
| 235 | } | 317 | } |
| 236 | 318 | ||
| 237 | void radeon_enable_interrupt(struct drm_device *dev) | ||
| 238 | { | ||
| 239 | drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private; | ||
| 240 | |||
| 241 | dev_priv->irq_enable_reg = RADEON_SW_INT_ENABLE; | ||
| 242 | if (dev_priv->vblank_crtc & DRM_RADEON_VBLANK_CRTC1) | ||
| 243 | dev_priv->irq_enable_reg |= RADEON_CRTC_VBLANK_MASK; | ||
| 244 | |||
| 245 | if (dev_priv->vblank_crtc & DRM_RADEON_VBLANK_CRTC2) | ||
| 246 | dev_priv->irq_enable_reg |= RADEON_CRTC2_VBLANK_MASK; | ||
| 247 | |||
| 248 | RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg); | ||
| 249 | dev_priv->irq_enabled = 1; | ||
| 250 | } | ||
| 251 | |||
| 252 | /* drm_dma.h hooks | 319 | /* drm_dma.h hooks |
| 253 | */ | 320 | */ |
| 254 | void radeon_driver_irq_preinstall(struct drm_device * dev) | 321 | void radeon_driver_irq_preinstall(struct drm_device * dev) |
| 255 | { | 322 | { |
| 256 | drm_radeon_private_t *dev_priv = | 323 | drm_radeon_private_t *dev_priv = |
| 257 | (drm_radeon_private_t *) dev->dev_private; | 324 | (drm_radeon_private_t *) dev->dev_private; |
| 325 | u32 dummy; | ||
| 258 | 326 | ||
| 259 | /* Disable *all* interrupts */ | 327 | /* Disable *all* interrupts */ |
| 328 | if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) | ||
| 329 | RADEON_WRITE(R500_DxMODE_INT_MASK, 0); | ||
| 260 | RADEON_WRITE(RADEON_GEN_INT_CNTL, 0); | 330 | RADEON_WRITE(RADEON_GEN_INT_CNTL, 0); |
| 261 | 331 | ||
| 262 | /* Clear bits if they're already high */ | 332 | /* Clear bits if they're already high */ |
| 263 | radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK | | 333 | radeon_acknowledge_irqs(dev_priv, &dummy); |
| 264 | RADEON_CRTC_VBLANK_STAT | | ||
| 265 | RADEON_CRTC2_VBLANK_STAT)); | ||
| 266 | } | 334 | } |
| 267 | 335 | ||
| 268 | void radeon_driver_irq_postinstall(struct drm_device * dev) | 336 | int radeon_driver_irq_postinstall(struct drm_device *dev) |
| 269 | { | 337 | { |
| 270 | drm_radeon_private_t *dev_priv = | 338 | drm_radeon_private_t *dev_priv = |
| 271 | (drm_radeon_private_t *) dev->dev_private; | 339 | (drm_radeon_private_t *) dev->dev_private; |
| 340 | int ret; | ||
| 272 | 341 | ||
| 273 | atomic_set(&dev_priv->swi_emitted, 0); | 342 | atomic_set(&dev_priv->swi_emitted, 0); |
| 274 | DRM_INIT_WAITQUEUE(&dev_priv->swi_queue); | 343 | DRM_INIT_WAITQUEUE(&dev_priv->swi_queue); |
| 275 | 344 | ||
| 276 | radeon_enable_interrupt(dev); | 345 | ret = drm_vblank_init(dev, 2); |
| 346 | if (ret) | ||
| 347 | return ret; | ||
| 348 | |||
| 349 | dev->max_vblank_count = 0x001fffff; | ||
| 350 | |||
| 351 | radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1); | ||
| 352 | |||
| 353 | return 0; | ||
| 277 | } | 354 | } |
| 278 | 355 | ||
| 279 | void radeon_driver_irq_uninstall(struct drm_device * dev) | 356 | void radeon_driver_irq_uninstall(struct drm_device * dev) |
| @@ -285,6 +362,8 @@ void radeon_driver_irq_uninstall(struct drm_device * dev) | |||
| 285 | 362 | ||
| 286 | dev_priv->irq_enabled = 0; | 363 | dev_priv->irq_enabled = 0; |
| 287 | 364 | ||
| 365 | if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) | ||
| 366 | RADEON_WRITE(R500_DxMODE_INT_MASK, 0); | ||
| 288 | /* Disable *all* interrupts */ | 367 | /* Disable *all* interrupts */ |
| 289 | RADEON_WRITE(RADEON_GEN_INT_CNTL, 0); | 368 | RADEON_WRITE(RADEON_GEN_INT_CNTL, 0); |
| 290 | } | 369 | } |
| @@ -293,18 +372,8 @@ void radeon_driver_irq_uninstall(struct drm_device * dev) | |||
| 293 | int radeon_vblank_crtc_get(struct drm_device *dev) | 372 | int radeon_vblank_crtc_get(struct drm_device *dev) |
| 294 | { | 373 | { |
| 295 | drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private; | 374 | drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private; |
| 296 | u32 flag; | ||
| 297 | u32 value; | ||
| 298 | |||
| 299 | flag = RADEON_READ(RADEON_GEN_INT_CNTL); | ||
| 300 | value = 0; | ||
| 301 | |||
| 302 | if (flag & RADEON_CRTC_VBLANK_MASK) | ||
| 303 | value |= DRM_RADEON_VBLANK_CRTC1; | ||
| 304 | 375 | ||
| 305 | if (flag & RADEON_CRTC2_VBLANK_MASK) | 376 | return dev_priv->vblank_crtc; |
| 306 | value |= DRM_RADEON_VBLANK_CRTC2; | ||
| 307 | return value; | ||
| 308 | } | 377 | } |
| 309 | 378 | ||
| 310 | int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value) | 379 | int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value) |
| @@ -315,6 +384,5 @@ int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value) | |||
| 315 | return -EINVAL; | 384 | return -EINVAL; |
| 316 | } | 385 | } |
| 317 | dev_priv->vblank_crtc = (unsigned int)value; | 386 | dev_priv->vblank_crtc = (unsigned int)value; |
| 318 | radeon_enable_interrupt(dev); | ||
| 319 | return 0; | 387 | return 0; |
| 320 | } | 388 | } |
diff --git a/drivers/gpu/drm/via/via_drv.c b/drivers/gpu/drm/via/via_drv.c index 80c01cdfa37d..0993b441fc42 100644 --- a/drivers/gpu/drm/via/via_drv.c +++ b/drivers/gpu/drm/via/via_drv.c | |||
| @@ -40,11 +40,13 @@ static struct pci_device_id pciidlist[] = { | |||
| 40 | static struct drm_driver driver = { | 40 | static struct drm_driver driver = { |
| 41 | .driver_features = | 41 | .driver_features = |
| 42 | DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_IRQ | | 42 | DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_IRQ | |
| 43 | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL, | 43 | DRIVER_IRQ_SHARED, |
| 44 | .load = via_driver_load, | 44 | .load = via_driver_load, |
| 45 | .unload = via_driver_unload, | 45 | .unload = via_driver_unload, |
| 46 | .context_dtor = via_final_context, | 46 | .context_dtor = via_final_context, |
| 47 | .vblank_wait = via_driver_vblank_wait, | 47 | .get_vblank_counter = via_get_vblank_counter, |
| 48 | .enable_vblank = via_enable_vblank, | ||
| 49 | .disable_vblank = via_disable_vblank, | ||
| 48 | .irq_preinstall = via_driver_irq_preinstall, | 50 | .irq_preinstall = via_driver_irq_preinstall, |
| 49 | .irq_postinstall = via_driver_irq_postinstall, | 51 | .irq_postinstall = via_driver_irq_postinstall, |
| 50 | .irq_uninstall = via_driver_irq_uninstall, | 52 | .irq_uninstall = via_driver_irq_uninstall, |
| @@ -59,17 +61,17 @@ static struct drm_driver driver = { | |||
| 59 | .get_reg_ofs = drm_core_get_reg_ofs, | 61 | .get_reg_ofs = drm_core_get_reg_ofs, |
| 60 | .ioctls = via_ioctls, | 62 | .ioctls = via_ioctls, |
| 61 | .fops = { | 63 | .fops = { |
| 62 | .owner = THIS_MODULE, | 64 | .owner = THIS_MODULE, |
| 63 | .open = drm_open, | 65 | .open = drm_open, |
| 64 | .release = drm_release, | 66 | .release = drm_release, |
| 65 | .ioctl = drm_ioctl, | 67 | .ioctl = drm_ioctl, |
| 66 | .mmap = drm_mmap, | 68 | .mmap = drm_mmap, |
| 67 | .poll = drm_poll, | 69 | .poll = drm_poll, |
| 68 | .fasync = drm_fasync, | 70 | .fasync = drm_fasync, |
| 69 | }, | 71 | }, |
| 70 | .pci_driver = { | 72 | .pci_driver = { |
| 71 | .name = DRIVER_NAME, | 73 | .name = DRIVER_NAME, |
| 72 | .id_table = pciidlist, | 74 | .id_table = pciidlist, |
| 73 | }, | 75 | }, |
| 74 | 76 | ||
| 75 | .name = DRIVER_NAME, | 77 | .name = DRIVER_NAME, |
diff --git a/drivers/gpu/drm/via/via_drv.h b/drivers/gpu/drm/via/via_drv.h index 2daae81874cd..cafcb844a223 100644 --- a/drivers/gpu/drm/via/via_drv.h +++ b/drivers/gpu/drm/via/via_drv.h | |||
| @@ -75,6 +75,7 @@ typedef struct drm_via_private { | |||
| 75 | struct timeval last_vblank; | 75 | struct timeval last_vblank; |
| 76 | int last_vblank_valid; | 76 | int last_vblank_valid; |
| 77 | unsigned usec_per_vblank; | 77 | unsigned usec_per_vblank; |
| 78 | atomic_t vbl_received; | ||
| 78 | drm_via_state_t hc_state; | 79 | drm_via_state_t hc_state; |
| 79 | char pci_buf[VIA_PCI_BUF_SIZE]; | 80 | char pci_buf[VIA_PCI_BUF_SIZE]; |
| 80 | const uint32_t *fire_offsets[VIA_FIRE_BUF_SIZE]; | 81 | const uint32_t *fire_offsets[VIA_FIRE_BUF_SIZE]; |
| @@ -130,21 +131,24 @@ extern int via_init_context(struct drm_device * dev, int context); | |||
| 130 | extern int via_final_context(struct drm_device * dev, int context); | 131 | extern int via_final_context(struct drm_device * dev, int context); |
| 131 | 132 | ||
| 132 | extern int via_do_cleanup_map(struct drm_device * dev); | 133 | extern int via_do_cleanup_map(struct drm_device * dev); |
| 133 | extern int via_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence); | 134 | extern u32 via_get_vblank_counter(struct drm_device *dev, int crtc); |
| 135 | extern int via_enable_vblank(struct drm_device *dev, int crtc); | ||
| 136 | extern void via_disable_vblank(struct drm_device *dev, int crtc); | ||
| 134 | 137 | ||
| 135 | extern irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS); | 138 | extern irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS); |
| 136 | extern void via_driver_irq_preinstall(struct drm_device * dev); | 139 | extern void via_driver_irq_preinstall(struct drm_device * dev); |
| 137 | extern void via_driver_irq_postinstall(struct drm_device * dev); | 140 | extern int via_driver_irq_postinstall(struct drm_device *dev); |
| 138 | extern void via_driver_irq_uninstall(struct drm_device * dev); | 141 | extern void via_driver_irq_uninstall(struct drm_device * dev); |
| 139 | 142 | ||
| 140 | extern int via_dma_cleanup(struct drm_device * dev); | 143 | extern int via_dma_cleanup(struct drm_device * dev); |
| 141 | extern void via_init_command_verifier(void); | 144 | extern void via_init_command_verifier(void); |
| 142 | extern int via_driver_dma_quiescent(struct drm_device * dev); | 145 | extern int via_driver_dma_quiescent(struct drm_device * dev); |
| 143 | extern void via_init_futex(drm_via_private_t * dev_priv); | 146 | extern void via_init_futex(drm_via_private_t *dev_priv); |
| 144 | extern void via_cleanup_futex(drm_via_private_t * dev_priv); | 147 | extern void via_cleanup_futex(drm_via_private_t *dev_priv); |
| 145 | extern void via_release_futex(drm_via_private_t * dev_priv, int context); | 148 | extern void via_release_futex(drm_via_private_t *dev_priv, int context); |
| 146 | 149 | ||
| 147 | extern void via_reclaim_buffers_locked(struct drm_device *dev, struct drm_file *file_priv); | 150 | extern void via_reclaim_buffers_locked(struct drm_device *dev, |
| 151 | struct drm_file *file_priv); | ||
| 148 | extern void via_lastclose(struct drm_device *dev); | 152 | extern void via_lastclose(struct drm_device *dev); |
| 149 | 153 | ||
| 150 | extern void via_dmablit_handler(struct drm_device *dev, int engine, int from_irq); | 154 | extern void via_dmablit_handler(struct drm_device *dev, int engine, int from_irq); |
diff --git a/drivers/gpu/drm/via/via_irq.c b/drivers/gpu/drm/via/via_irq.c index c6bb978a1106..1b966fbdb49f 100644 --- a/drivers/gpu/drm/via/via_irq.c +++ b/drivers/gpu/drm/via/via_irq.c | |||
| @@ -43,7 +43,7 @@ | |||
| 43 | #define VIA_REG_INTERRUPT 0x200 | 43 | #define VIA_REG_INTERRUPT 0x200 |
| 44 | 44 | ||
| 45 | /* VIA_REG_INTERRUPT */ | 45 | /* VIA_REG_INTERRUPT */ |
| 46 | #define VIA_IRQ_GLOBAL (1 << 31) | 46 | #define VIA_IRQ_GLOBAL (1 << 31) |
| 47 | #define VIA_IRQ_VBLANK_ENABLE (1 << 19) | 47 | #define VIA_IRQ_VBLANK_ENABLE (1 << 19) |
| 48 | #define VIA_IRQ_VBLANK_PENDING (1 << 3) | 48 | #define VIA_IRQ_VBLANK_PENDING (1 << 3) |
| 49 | #define VIA_IRQ_HQV0_ENABLE (1 << 11) | 49 | #define VIA_IRQ_HQV0_ENABLE (1 << 11) |
| @@ -68,16 +68,15 @@ | |||
| 68 | 68 | ||
| 69 | static maskarray_t via_pro_group_a_irqs[] = { | 69 | static maskarray_t via_pro_group_a_irqs[] = { |
| 70 | {VIA_IRQ_HQV0_ENABLE, VIA_IRQ_HQV0_PENDING, 0x000003D0, 0x00008010, | 70 | {VIA_IRQ_HQV0_ENABLE, VIA_IRQ_HQV0_PENDING, 0x000003D0, 0x00008010, |
| 71 | 0x00000000}, | 71 | 0x00000000 }, |
| 72 | {VIA_IRQ_HQV1_ENABLE, VIA_IRQ_HQV1_PENDING, 0x000013D0, 0x00008010, | 72 | {VIA_IRQ_HQV1_ENABLE, VIA_IRQ_HQV1_PENDING, 0x000013D0, 0x00008010, |
| 73 | 0x00000000}, | 73 | 0x00000000 }, |
| 74 | {VIA_IRQ_DMA0_TD_ENABLE, VIA_IRQ_DMA0_TD_PENDING, VIA_PCI_DMA_CSR0, | 74 | {VIA_IRQ_DMA0_TD_ENABLE, VIA_IRQ_DMA0_TD_PENDING, VIA_PCI_DMA_CSR0, |
| 75 | VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008}, | 75 | VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008}, |
| 76 | {VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1, | 76 | {VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1, |
| 77 | VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008}, | 77 | VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008}, |
| 78 | }; | 78 | }; |
| 79 | static int via_num_pro_group_a = | 79 | static int via_num_pro_group_a = ARRAY_SIZE(via_pro_group_a_irqs); |
| 80 | sizeof(via_pro_group_a_irqs) / sizeof(maskarray_t); | ||
| 81 | static int via_irqmap_pro_group_a[] = {0, 1, -1, 2, -1, 3}; | 80 | static int via_irqmap_pro_group_a[] = {0, 1, -1, 2, -1, 3}; |
| 82 | 81 | ||
| 83 | static maskarray_t via_unichrome_irqs[] = { | 82 | static maskarray_t via_unichrome_irqs[] = { |
| @@ -86,14 +85,24 @@ static maskarray_t via_unichrome_irqs[] = { | |||
| 86 | {VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1, | 85 | {VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1, |
| 87 | VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008} | 86 | VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008} |
| 88 | }; | 87 | }; |
| 89 | static int via_num_unichrome = sizeof(via_unichrome_irqs) / sizeof(maskarray_t); | 88 | static int via_num_unichrome = ARRAY_SIZE(via_unichrome_irqs); |
| 90 | static int via_irqmap_unichrome[] = {-1, -1, -1, 0, -1, 1}; | 89 | static int via_irqmap_unichrome[] = {-1, -1, -1, 0, -1, 1}; |
| 91 | 90 | ||
| 91 | |||
| 92 | static unsigned time_diff(struct timeval *now, struct timeval *then) | 92 | static unsigned time_diff(struct timeval *now, struct timeval *then) |
| 93 | { | 93 | { |
| 94 | return (now->tv_usec >= then->tv_usec) ? | 94 | return (now->tv_usec >= then->tv_usec) ? |
| 95 | now->tv_usec - then->tv_usec : | 95 | now->tv_usec - then->tv_usec : |
| 96 | 1000000 - (then->tv_usec - now->tv_usec); | 96 | 1000000 - (then->tv_usec - now->tv_usec); |
| 97 | } | ||
| 98 | |||
| 99 | u32 via_get_vblank_counter(struct drm_device *dev, int crtc) | ||
| 100 | { | ||
| 101 | drm_via_private_t *dev_priv = dev->dev_private; | ||
| 102 | if (crtc != 0) | ||
| 103 | return 0; | ||
| 104 | |||
| 105 | return atomic_read(&dev_priv->vbl_received); | ||
| 97 | } | 106 | } |
| 98 | 107 | ||
| 99 | irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS) | 108 | irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS) |
| @@ -108,23 +117,22 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS) | |||
| 108 | 117 | ||
| 109 | status = VIA_READ(VIA_REG_INTERRUPT); | 118 | status = VIA_READ(VIA_REG_INTERRUPT); |
| 110 | if (status & VIA_IRQ_VBLANK_PENDING) { | 119 | if (status & VIA_IRQ_VBLANK_PENDING) { |
| 111 | atomic_inc(&dev->vbl_received); | 120 | atomic_inc(&dev_priv->vbl_received); |
| 112 | if (!(atomic_read(&dev->vbl_received) & 0x0F)) { | 121 | if (!(atomic_read(&dev_priv->vbl_received) & 0x0F)) { |
| 113 | do_gettimeofday(&cur_vblank); | 122 | do_gettimeofday(&cur_vblank); |
| 114 | if (dev_priv->last_vblank_valid) { | 123 | if (dev_priv->last_vblank_valid) { |
| 115 | dev_priv->usec_per_vblank = | 124 | dev_priv->usec_per_vblank = |
| 116 | time_diff(&cur_vblank, | 125 | time_diff(&cur_vblank, |
| 117 | &dev_priv->last_vblank) >> 4; | 126 | &dev_priv->last_vblank) >> 4; |
| 118 | } | 127 | } |
| 119 | dev_priv->last_vblank = cur_vblank; | 128 | dev_priv->last_vblank = cur_vblank; |
| 120 | dev_priv->last_vblank_valid = 1; | 129 | dev_priv->last_vblank_valid = 1; |
| 121 | } | 130 | } |
| 122 | if (!(atomic_read(&dev->vbl_received) & 0xFF)) { | 131 | if (!(atomic_read(&dev_priv->vbl_received) & 0xFF)) { |
| 123 | DRM_DEBUG("US per vblank is: %u\n", | 132 | DRM_DEBUG("US per vblank is: %u\n", |
| 124 | dev_priv->usec_per_vblank); | 133 | dev_priv->usec_per_vblank); |
| 125 | } | 134 | } |
| 126 | DRM_WAKEUP(&dev->vbl_queue); | 135 | drm_handle_vblank(dev, 0); |
| 127 | drm_vbl_send_signals(dev); | ||
| 128 | handled = 1; | 136 | handled = 1; |
| 129 | } | 137 | } |
| 130 | 138 | ||
| @@ -145,6 +153,7 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS) | |||
| 145 | /* Acknowlege interrupts */ | 153 | /* Acknowlege interrupts */ |
| 146 | VIA_WRITE(VIA_REG_INTERRUPT, status); | 154 | VIA_WRITE(VIA_REG_INTERRUPT, status); |
| 147 | 155 | ||
| 156 | |||
| 148 | if (handled) | 157 | if (handled) |
| 149 | return IRQ_HANDLED; | 158 | return IRQ_HANDLED; |
| 150 | else | 159 | else |
| @@ -163,31 +172,34 @@ static __inline__ void viadrv_acknowledge_irqs(drm_via_private_t * dev_priv) | |||
| 163 | } | 172 | } |
| 164 | } | 173 | } |
| 165 | 174 | ||
| 166 | int via_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence) | 175 | int via_enable_vblank(struct drm_device *dev, int crtc) |
| 167 | { | 176 | { |
| 168 | drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; | 177 | drm_via_private_t *dev_priv = dev->dev_private; |
| 169 | unsigned int cur_vblank; | 178 | u32 status; |
| 170 | int ret = 0; | ||
| 171 | 179 | ||
| 172 | DRM_DEBUG("\n"); | 180 | if (crtc != 0) { |
| 173 | if (!dev_priv) { | 181 | DRM_ERROR("%s: bad crtc %d\n", __func__, crtc); |
| 174 | DRM_ERROR("called with no initialization\n"); | ||
| 175 | return -EINVAL; | 182 | return -EINVAL; |
| 176 | } | 183 | } |
| 177 | 184 | ||
| 178 | viadrv_acknowledge_irqs(dev_priv); | 185 | status = VIA_READ(VIA_REG_INTERRUPT); |
| 186 | VIA_WRITE(VIA_REG_INTERRUPT, status & VIA_IRQ_VBLANK_ENABLE); | ||
| 187 | |||
| 188 | VIA_WRITE8(0x83d4, 0x11); | ||
| 189 | VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30); | ||
| 179 | 190 | ||
| 180 | /* Assume that the user has missed the current sequence number | 191 | return 0; |
| 181 | * by about a day rather than she wants to wait for years | 192 | } |
| 182 | * using vertical blanks... | ||
| 183 | */ | ||
| 184 | 193 | ||
| 185 | DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, | 194 | void via_disable_vblank(struct drm_device *dev, int crtc) |
| 186 | (((cur_vblank = atomic_read(&dev->vbl_received)) - | 195 | { |
| 187 | *sequence) <= (1 << 23))); | 196 | drm_via_private_t *dev_priv = dev->dev_private; |
| 188 | 197 | ||
| 189 | *sequence = cur_vblank; | 198 | VIA_WRITE8(0x83d4, 0x11); |
| 190 | return ret; | 199 | VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) & ~0x30); |
| 200 | |||
| 201 | if (crtc != 0) | ||
| 202 | DRM_ERROR("%s: bad crtc %d\n", __func__, crtc); | ||
| 191 | } | 203 | } |
| 192 | 204 | ||
| 193 | static int | 205 | static int |
| @@ -239,6 +251,7 @@ via_driver_irq_wait(struct drm_device * dev, unsigned int irq, int force_sequenc | |||
| 239 | return ret; | 251 | return ret; |
| 240 | } | 252 | } |
| 241 | 253 | ||
| 254 | |||
| 242 | /* | 255 | /* |
| 243 | * drm_dma.h hooks | 256 | * drm_dma.h hooks |
| 244 | */ | 257 | */ |
| @@ -292,23 +305,25 @@ void via_driver_irq_preinstall(struct drm_device * dev) | |||
| 292 | } | 305 | } |
| 293 | } | 306 | } |
| 294 | 307 | ||
| 295 | void via_driver_irq_postinstall(struct drm_device * dev) | 308 | int via_driver_irq_postinstall(struct drm_device *dev) |
| 296 | { | 309 | { |
| 297 | drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; | 310 | drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; |
| 298 | u32 status; | 311 | u32 status; |
| 299 | 312 | ||
| 300 | DRM_DEBUG("\n"); | 313 | DRM_DEBUG("via_driver_irq_postinstall\n"); |
| 301 | if (dev_priv) { | 314 | if (!dev_priv) |
| 302 | status = VIA_READ(VIA_REG_INTERRUPT); | 315 | return -EINVAL; |
| 303 | VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL | ||
| 304 | | dev_priv->irq_enable_mask); | ||
| 305 | 316 | ||
| 306 | /* Some magic, oh for some data sheets ! */ | 317 | drm_vblank_init(dev, 1); |
| 318 | status = VIA_READ(VIA_REG_INTERRUPT); | ||
| 319 | VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL | ||
| 320 | | dev_priv->irq_enable_mask); | ||
| 307 | 321 | ||
| 308 | VIA_WRITE8(0x83d4, 0x11); | 322 | /* Some magic, oh for some data sheets ! */ |
| 309 | VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30); | 323 | VIA_WRITE8(0x83d4, 0x11); |
| 324 | VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30); | ||
| 310 | 325 | ||
| 311 | } | 326 | return 0; |
| 312 | } | 327 | } |
| 313 | 328 | ||
| 314 | void via_driver_irq_uninstall(struct drm_device * dev) | 329 | void via_driver_irq_uninstall(struct drm_device * dev) |
| @@ -352,7 +367,8 @@ int via_wait_irq(struct drm_device *dev, void *data, struct drm_file *file_priv) | |||
| 352 | 367 | ||
| 353 | switch (irqwait->request.type & ~VIA_IRQ_FLAGS_MASK) { | 368 | switch (irqwait->request.type & ~VIA_IRQ_FLAGS_MASK) { |
| 354 | case VIA_IRQ_RELATIVE: | 369 | case VIA_IRQ_RELATIVE: |
| 355 | irqwait->request.sequence += atomic_read(&cur_irq->irq_received); | 370 | irqwait->request.sequence += |
| 371 | atomic_read(&cur_irq->irq_received); | ||
| 356 | irqwait->request.type &= ~_DRM_VBLANK_RELATIVE; | 372 | irqwait->request.type &= ~_DRM_VBLANK_RELATIVE; |
| 357 | case VIA_IRQ_ABSOLUTE: | 373 | case VIA_IRQ_ABSOLUTE: |
| 358 | break; | 374 | break; |
diff --git a/include/drm/drm.h b/include/drm/drm.h index 0864c6920941..15e55039b7f1 100644 --- a/include/drm/drm.h +++ b/include/drm/drm.h | |||
| @@ -454,6 +454,7 @@ struct drm_irq_busid { | |||
| 454 | enum drm_vblank_seq_type { | 454 | enum drm_vblank_seq_type { |
| 455 | _DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ | 455 | _DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ |
| 456 | _DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ | 456 | _DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ |
| 457 | _DRM_VBLANK_FLIP = 0x8000000, /**< Scheduled buffer swap should flip */ | ||
| 457 | _DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */ | 458 | _DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */ |
| 458 | _DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ | 459 | _DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ |
| 459 | _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */ | 460 | _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */ |
| @@ -486,6 +487,19 @@ union drm_wait_vblank { | |||
| 486 | struct drm_wait_vblank_reply reply; | 487 | struct drm_wait_vblank_reply reply; |
| 487 | }; | 488 | }; |
| 488 | 489 | ||
| 490 | #define _DRM_PRE_MODESET 1 | ||
| 491 | #define _DRM_POST_MODESET 2 | ||
| 492 | |||
| 493 | /** | ||
| 494 | * DRM_IOCTL_MODESET_CTL ioctl argument type | ||
| 495 | * | ||
| 496 | * \sa drmModesetCtl(). | ||
| 497 | */ | ||
| 498 | struct drm_modeset_ctl { | ||
| 499 | uint32_t crtc; | ||
| 500 | uint32_t cmd; | ||
| 501 | }; | ||
| 502 | |||
| 489 | /** | 503 | /** |
| 490 | * DRM_IOCTL_AGP_ENABLE ioctl argument type. | 504 | * DRM_IOCTL_AGP_ENABLE ioctl argument type. |
| 491 | * | 505 | * |
| @@ -570,6 +584,7 @@ struct drm_set_version { | |||
| 570 | #define DRM_IOCTL_GET_CLIENT DRM_IOWR(0x05, struct drm_client) | 584 | #define DRM_IOCTL_GET_CLIENT DRM_IOWR(0x05, struct drm_client) |
| 571 | #define DRM_IOCTL_GET_STATS DRM_IOR( 0x06, struct drm_stats) | 585 | #define DRM_IOCTL_GET_STATS DRM_IOR( 0x06, struct drm_stats) |
| 572 | #define DRM_IOCTL_SET_VERSION DRM_IOWR(0x07, struct drm_set_version) | 586 | #define DRM_IOCTL_SET_VERSION DRM_IOWR(0x07, struct drm_set_version) |
| 587 | #define DRM_IOCTL_MODESET_CTL DRM_IOW(0x08, struct drm_modeset_ctl) | ||
| 573 | 588 | ||
| 574 | #define DRM_IOCTL_SET_UNIQUE DRM_IOW( 0x10, struct drm_unique) | 589 | #define DRM_IOCTL_SET_UNIQUE DRM_IOW( 0x10, struct drm_unique) |
| 575 | #define DRM_IOCTL_AUTH_MAGIC DRM_IOW( 0x11, struct drm_auth) | 590 | #define DRM_IOCTL_AUTH_MAGIC DRM_IOW( 0x11, struct drm_auth) |
diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 1c1b13e29223..e79ce0781f0b 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h | |||
| @@ -580,11 +580,54 @@ struct drm_driver { | |||
| 580 | int (*kernel_context_switch) (struct drm_device *dev, int old, | 580 | int (*kernel_context_switch) (struct drm_device *dev, int old, |
| 581 | int new); | 581 | int new); |
| 582 | void (*kernel_context_switch_unlock) (struct drm_device *dev); | 582 | void (*kernel_context_switch_unlock) (struct drm_device *dev); |
| 583 | int (*vblank_wait) (struct drm_device *dev, unsigned int *sequence); | ||
| 584 | int (*vblank_wait2) (struct drm_device *dev, unsigned int *sequence); | ||
| 585 | int (*dri_library_name) (struct drm_device *dev, char *buf); | 583 | int (*dri_library_name) (struct drm_device *dev, char *buf); |
| 586 | 584 | ||
| 587 | /** | 585 | /** |
| 586 | * get_vblank_counter - get raw hardware vblank counter | ||
| 587 | * @dev: DRM device | ||
| 588 | * @crtc: counter to fetch | ||
| 589 | * | ||
| 590 | * Driver callback for fetching a raw hardware vblank counter | ||
| 591 | * for @crtc. If a device doesn't have a hardware counter, the | ||
| 592 | * driver can simply return the value of drm_vblank_count and | ||
| 593 | * make the enable_vblank() and disable_vblank() hooks into no-ops, | ||
| 594 | * leaving interrupts enabled at all times. | ||
| 595 | * | ||
| 596 | * Wraparound handling and loss of events due to modesetting is dealt | ||
| 597 | * with in the DRM core code. | ||
| 598 | * | ||
| 599 | * RETURNS | ||
| 600 | * Raw vblank counter value. | ||
| 601 | */ | ||
| 602 | u32 (*get_vblank_counter) (struct drm_device *dev, int crtc); | ||
| 603 | |||
| 604 | /** | ||
| 605 | * enable_vblank - enable vblank interrupt events | ||
| 606 | * @dev: DRM device | ||
| 607 | * @crtc: which irq to enable | ||
| 608 | * | ||
| 609 | * Enable vblank interrupts for @crtc. If the device doesn't have | ||
| 610 | * a hardware vblank counter, this routine should be a no-op, since | ||
| 611 | * interrupts will have to stay on to keep the count accurate. | ||
| 612 | * | ||
| 613 | * RETURNS | ||
| 614 | * Zero on success, appropriate errno if the given @crtc's vblank | ||
| 615 | * interrupt cannot be enabled. | ||
| 616 | */ | ||
| 617 | int (*enable_vblank) (struct drm_device *dev, int crtc); | ||
| 618 | |||
| 619 | /** | ||
| 620 | * disable_vblank - disable vblank interrupt events | ||
| 621 | * @dev: DRM device | ||
| 622 | * @crtc: which irq to enable | ||
| 623 | * | ||
| 624 | * Disable vblank interrupts for @crtc. If the device doesn't have | ||
| 625 | * a hardware vblank counter, this routine should be a no-op, since | ||
| 626 | * interrupts will have to stay on to keep the count accurate. | ||
| 627 | */ | ||
| 628 | void (*disable_vblank) (struct drm_device *dev, int crtc); | ||
| 629 | |||
| 630 | /** | ||
| 588 | * Called by \c drm_device_is_agp. Typically used to determine if a | 631 | * Called by \c drm_device_is_agp. Typically used to determine if a |
| 589 | * card is really attached to AGP or not. | 632 | * card is really attached to AGP or not. |
| 590 | * | 633 | * |
| @@ -601,7 +644,7 @@ struct drm_driver { | |||
| 601 | 644 | ||
| 602 | irqreturn_t(*irq_handler) (DRM_IRQ_ARGS); | 645 | irqreturn_t(*irq_handler) (DRM_IRQ_ARGS); |
| 603 | void (*irq_preinstall) (struct drm_device *dev); | 646 | void (*irq_preinstall) (struct drm_device *dev); |
| 604 | void (*irq_postinstall) (struct drm_device *dev); | 647 | int (*irq_postinstall) (struct drm_device *dev); |
| 605 | void (*irq_uninstall) (struct drm_device *dev); | 648 | void (*irq_uninstall) (struct drm_device *dev); |
| 606 | void (*reclaim_buffers) (struct drm_device *dev, | 649 | void (*reclaim_buffers) (struct drm_device *dev, |
| 607 | struct drm_file * file_priv); | 650 | struct drm_file * file_priv); |
| @@ -730,13 +773,28 @@ struct drm_device { | |||
| 730 | /** \name VBLANK IRQ support */ | 773 | /** \name VBLANK IRQ support */ |
| 731 | /*@{ */ | 774 | /*@{ */ |
| 732 | 775 | ||
| 733 | wait_queue_head_t vbl_queue; /**< VBLANK wait queue */ | 776 | /* |
| 734 | atomic_t vbl_received; | 777 | * At load time, disabling the vblank interrupt won't be allowed since |
| 735 | atomic_t vbl_received2; /**< number of secondary VBLANK interrupts */ | 778 | * old clients may not call the modeset ioctl and therefore misbehave. |
| 779 | * Once the modeset ioctl *has* been called though, we can safely | ||
| 780 | * disable them when unused. | ||
| 781 | */ | ||
| 782 | int vblank_disable_allowed; | ||
| 783 | |||
| 784 | wait_queue_head_t *vbl_queue; /**< VBLANK wait queue */ | ||
| 785 | atomic_t *_vblank_count; /**< number of VBLANK interrupts (driver must alloc the right number of counters) */ | ||
| 736 | spinlock_t vbl_lock; | 786 | spinlock_t vbl_lock; |
| 737 | struct list_head vbl_sigs; /**< signal list to send on VBLANK */ | 787 | struct list_head *vbl_sigs; /**< signal list to send on VBLANK */ |
| 738 | struct list_head vbl_sigs2; /**< signals to send on secondary VBLANK */ | 788 | atomic_t vbl_signal_pending; /* number of signals pending on all crtcs*/ |
| 739 | unsigned int vbl_pending; | 789 | atomic_t *vblank_refcount; /* number of users of vblank interruptsper crtc */ |
| 790 | u32 *last_vblank; /* protected by dev->vbl_lock, used */ | ||
| 791 | /* for wraparound handling */ | ||
| 792 | int *vblank_enabled; /* so we don't call enable more than | ||
| 793 | once per disable */ | ||
| 794 | int *vblank_inmodeset; /* Display driver is setting mode */ | ||
| 795 | struct timer_list vblank_disable_timer; | ||
| 796 | |||
| 797 | u32 max_vblank_count; /**< size of vblank counter register */ | ||
| 740 | spinlock_t tasklet_lock; /**< For drm_locked_tasklet */ | 798 | spinlock_t tasklet_lock; /**< For drm_locked_tasklet */ |
| 741 | void (*locked_tasklet_func)(struct drm_device *dev); | 799 | void (*locked_tasklet_func)(struct drm_device *dev); |
| 742 | 800 | ||
| @@ -757,6 +815,7 @@ struct drm_device { | |||
| 757 | struct pci_controller *hose; | 815 | struct pci_controller *hose; |
| 758 | #endif | 816 | #endif |
| 759 | struct drm_sg_mem *sg; /**< Scatter gather memory */ | 817 | struct drm_sg_mem *sg; /**< Scatter gather memory */ |
| 818 | int num_crtcs; /**< Number of CRTCs on this device */ | ||
| 760 | void *dev_private; /**< device private data */ | 819 | void *dev_private; /**< device private data */ |
| 761 | struct drm_sigdata sigdata; /**< For block_all_signals */ | 820 | struct drm_sigdata sigdata; /**< For block_all_signals */ |
| 762 | sigset_t sigmask; | 821 | sigset_t sigmask; |
| @@ -990,10 +1049,19 @@ extern void drm_driver_irq_preinstall(struct drm_device *dev); | |||
| 990 | extern void drm_driver_irq_postinstall(struct drm_device *dev); | 1049 | extern void drm_driver_irq_postinstall(struct drm_device *dev); |
| 991 | extern void drm_driver_irq_uninstall(struct drm_device *dev); | 1050 | extern void drm_driver_irq_uninstall(struct drm_device *dev); |
| 992 | 1051 | ||
| 1052 | extern int drm_vblank_init(struct drm_device *dev, int num_crtcs); | ||
| 993 | extern int drm_wait_vblank(struct drm_device *dev, void *data, | 1053 | extern int drm_wait_vblank(struct drm_device *dev, void *data, |
| 994 | struct drm_file *file_priv); | 1054 | struct drm_file *filp); |
| 995 | extern int drm_vblank_wait(struct drm_device *dev, unsigned int *vbl_seq); | 1055 | extern int drm_vblank_wait(struct drm_device *dev, unsigned int *vbl_seq); |
| 996 | extern void drm_vbl_send_signals(struct drm_device *dev); | 1056 | extern void drm_locked_tasklet(struct drm_device *dev, |
| 1057 | void(*func)(struct drm_device *)); | ||
| 1058 | extern u32 drm_vblank_count(struct drm_device *dev, int crtc); | ||
| 1059 | extern void drm_handle_vblank(struct drm_device *dev, int crtc); | ||
| 1060 | extern int drm_vblank_get(struct drm_device *dev, int crtc); | ||
| 1061 | extern void drm_vblank_put(struct drm_device *dev, int crtc); | ||
| 1062 | /* Modesetting support */ | ||
| 1063 | extern int drm_modeset_ctl(struct drm_device *dev, void *data, | ||
| 1064 | struct drm_file *file_priv); | ||
| 997 | extern void drm_locked_tasklet(struct drm_device *dev, void(*func)(struct drm_device*)); | 1065 | extern void drm_locked_tasklet(struct drm_device *dev, void(*func)(struct drm_device*)); |
| 998 | 1066 | ||
| 999 | /* AGP/GART support (drm_agpsupport.h) */ | 1067 | /* AGP/GART support (drm_agpsupport.h) */ |
