diff options
| -rw-r--r-- | drivers/char/drm/drm.h | 17 | ||||
| -rw-r--r-- | drivers/char/drm/drmP.h | 91 | ||||
| -rw-r--r-- | drivers/char/drm/drm_fops.c | 7 | ||||
| -rw-r--r-- | drivers/char/drm/drm_irq.c | 381 | ||||
| -rw-r--r-- | drivers/char/drm/drm_lock.c | 35 | ||||
| -rw-r--r-- | drivers/char/drm/i915_dma.c | 160 | ||||
| -rw-r--r-- | drivers/char/drm/i915_drm.h | 45 | ||||
| -rw-r--r-- | drivers/char/drm/i915_drv.c | 23 | ||||
| -rw-r--r-- | drivers/char/drm/i915_drv.h | 115 | ||||
| -rw-r--r-- | drivers/char/drm/i915_irq.c | 597 | ||||
| -rw-r--r-- | drivers/char/drm/mga_drv.c | 7 | ||||
| -rw-r--r-- | drivers/char/drm/mga_drv.h | 6 | ||||
| -rw-r--r-- | drivers/char/drm/mga_irq.c | 69 | ||||
| -rw-r--r-- | drivers/char/drm/r128_drv.c | 7 | ||||
| -rw-r--r-- | drivers/char/drm/r128_drv.h | 9 | ||||
| -rw-r--r-- | drivers/char/drm/r128_irq.c | 55 | ||||
| -rw-r--r-- | drivers/char/drm/radeon_drv.c | 8 | ||||
| -rw-r--r-- | drivers/char/drm/radeon_drv.h | 19 | ||||
| -rw-r--r-- | drivers/char/drm/radeon_irq.c | 171 | ||||
| -rw-r--r-- | drivers/char/drm/via_drv.c | 6 | ||||
| -rw-r--r-- | drivers/char/drm/via_drv.h | 7 | ||||
| -rw-r--r-- | drivers/char/drm/via_irq.c | 81 |
22 files changed, 513 insertions, 1403 deletions
diff --git a/drivers/char/drm/drm.h b/drivers/char/drm/drm.h index 6874f31ca8c..3a05c6d5ebe 100644 --- a/drivers/char/drm/drm.h +++ b/drivers/char/drm/drm.h | |||
| @@ -471,7 +471,6 @@ struct drm_irq_busid { | |||
| 471 | enum drm_vblank_seq_type { | 471 | enum drm_vblank_seq_type { |
| 472 | _DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ | 472 | _DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ |
| 473 | _DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ | 473 | _DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ |
| 474 | _DRM_VBLANK_FLIP = 0x8000000, /**< Scheduled buffer swap should flip */ | ||
| 475 | _DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */ | 474 | _DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */ |
| 476 | _DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ | 475 | _DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ |
| 477 | _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */ | 476 | _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */ |
| @@ -504,21 +503,6 @@ union drm_wait_vblank { | |||
| 504 | struct drm_wait_vblank_reply reply; | 503 | struct drm_wait_vblank_reply reply; |
| 505 | }; | 504 | }; |
| 506 | 505 | ||
| 507 | enum drm_modeset_ctl_cmd { | ||
| 508 | _DRM_PRE_MODESET = 1, | ||
| 509 | _DRM_POST_MODESET = 2, | ||
| 510 | }; | ||
| 511 | |||
| 512 | /** | ||
| 513 | * DRM_IOCTL_MODESET_CTL ioctl argument type | ||
| 514 | * | ||
| 515 | * \sa drmModesetCtl(). | ||
| 516 | */ | ||
| 517 | struct drm_modeset_ctl { | ||
| 518 | unsigned long arg; | ||
| 519 | enum drm_modeset_ctl_cmd cmd; | ||
| 520 | }; | ||
| 521 | |||
| 522 | /** | 506 | /** |
| 523 | * DRM_IOCTL_AGP_ENABLE ioctl argument type. | 507 | * DRM_IOCTL_AGP_ENABLE ioctl argument type. |
| 524 | * | 508 | * |
| @@ -603,7 +587,6 @@ struct drm_set_version { | |||
| 603 | #define DRM_IOCTL_GET_CLIENT DRM_IOWR(0x05, struct drm_client) | 587 | #define DRM_IOCTL_GET_CLIENT DRM_IOWR(0x05, struct drm_client) |
| 604 | #define DRM_IOCTL_GET_STATS DRM_IOR( 0x06, struct drm_stats) | 588 | #define DRM_IOCTL_GET_STATS DRM_IOR( 0x06, struct drm_stats) |
| 605 | #define DRM_IOCTL_SET_VERSION DRM_IOWR(0x07, struct drm_set_version) | 589 | #define DRM_IOCTL_SET_VERSION DRM_IOWR(0x07, struct drm_set_version) |
| 606 | #define DRM_IOCTL_MODESET_CTL DRM_IOW(0x08, struct drm_modeset_ctl) | ||
| 607 | 590 | ||
| 608 | #define DRM_IOCTL_SET_UNIQUE DRM_IOW( 0x10, struct drm_unique) | 591 | #define DRM_IOCTL_SET_UNIQUE DRM_IOW( 0x10, struct drm_unique) |
| 609 | #define DRM_IOCTL_AUTH_MAGIC DRM_IOW( 0x11, struct drm_auth) | 592 | #define DRM_IOCTL_AUTH_MAGIC DRM_IOW( 0x11, struct drm_auth) |
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index 213b3ca3468..0764b662b33 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h | |||
| @@ -100,8 +100,10 @@ struct drm_device; | |||
| 100 | #define DRIVER_HAVE_DMA 0x20 | 100 | #define DRIVER_HAVE_DMA 0x20 |
| 101 | #define DRIVER_HAVE_IRQ 0x40 | 101 | #define DRIVER_HAVE_IRQ 0x40 |
| 102 | #define DRIVER_IRQ_SHARED 0x80 | 102 | #define DRIVER_IRQ_SHARED 0x80 |
| 103 | #define DRIVER_IRQ_VBL 0x100 | ||
| 103 | #define DRIVER_DMA_QUEUE 0x200 | 104 | #define DRIVER_DMA_QUEUE 0x200 |
| 104 | #define DRIVER_FB_DMA 0x400 | 105 | #define DRIVER_FB_DMA 0x400 |
| 106 | #define DRIVER_IRQ_VBL2 0x800 | ||
| 105 | 107 | ||
| 106 | /***********************************************************************/ | 108 | /***********************************************************************/ |
| 107 | /** \name Begin the DRM... */ | 109 | /** \name Begin the DRM... */ |
| @@ -577,52 +579,10 @@ struct drm_driver { | |||
| 577 | int (*context_dtor) (struct drm_device *dev, int context); | 579 | int (*context_dtor) (struct drm_device *dev, int context); |
| 578 | int (*kernel_context_switch) (struct drm_device *dev, int old, | 580 | int (*kernel_context_switch) (struct drm_device *dev, int old, |
| 579 | int new); | 581 | int new); |
| 580 | void (*kernel_context_switch_unlock) (struct drm_device * dev); | 582 | void (*kernel_context_switch_unlock) (struct drm_device *dev); |
| 581 | /** | 583 | int (*vblank_wait) (struct drm_device *dev, unsigned int *sequence); |
| 582 | * get_vblank_counter - get raw hardware vblank counter | 584 | int (*vblank_wait2) (struct drm_device *dev, unsigned int *sequence); |
| 583 | * @dev: DRM device | 585 | int (*dri_library_name) (struct drm_device *dev, char *buf); |
| 584 | * @crtc: counter to fetch | ||
| 585 | * | ||
| 586 | * Driver callback for fetching a raw hardware vblank counter | ||
| 587 | * for @crtc. If a device doesn't have a hardware counter, the | ||
| 588 | * driver can simply return the value of drm_vblank_count and | ||
| 589 | * make the enable_vblank() and disable_vblank() hooks into no-ops, | ||
| 590 | * leaving interrupts enabled at all times. | ||
| 591 | * | ||
| 592 | * Wraparound handling and loss of events due to modesetting is dealt | ||
| 593 | * with in the DRM core code. | ||
| 594 | * | ||
| 595 | * RETURNS | ||
| 596 | * Raw vblank counter value. | ||
| 597 | */ | ||
| 598 | u32 (*get_vblank_counter) (struct drm_device *dev, int crtc); | ||
| 599 | |||
| 600 | /** | ||
| 601 | * enable_vblank - enable vblank interrupt events | ||
| 602 | * @dev: DRM device | ||
| 603 | * @crtc: which irq to enable | ||
| 604 | * | ||
| 605 | * Enable vblank interrupts for @crtc. If the device doesn't have | ||
| 606 | * a hardware vblank counter, this routine should be a no-op, since | ||
| 607 | * interrupts will have to stay on to keep the count accurate. | ||
| 608 | * | ||
| 609 | * RETURNS | ||
| 610 | * Zero on success, appropriate errno if the given @crtc's vblank | ||
| 611 | * interrupt cannot be enabled. | ||
| 612 | */ | ||
| 613 | int (*enable_vblank) (struct drm_device *dev, int crtc); | ||
| 614 | |||
| 615 | /** | ||
| 616 | * disable_vblank - disable vblank interrupt events | ||
| 617 | * @dev: DRM device | ||
| 618 | * @crtc: which irq to enable | ||
| 619 | * | ||
| 620 | * Disable vblank interrupts for @crtc. If the device doesn't have | ||
| 621 | * a hardware vblank counter, this routine should be a no-op, since | ||
| 622 | * interrupts will have to stay on to keep the count accurate. | ||
| 623 | */ | ||
| 624 | void (*disable_vblank) (struct drm_device *dev, int crtc); | ||
| 625 | int (*dri_library_name) (struct drm_device *dev, char * buf); | ||
| 626 | 586 | ||
| 627 | /** | 587 | /** |
| 628 | * Called by \c drm_device_is_agp. Typically used to determine if a | 588 | * Called by \c drm_device_is_agp. Typically used to determine if a |
| @@ -641,7 +601,7 @@ struct drm_driver { | |||
| 641 | 601 | ||
| 642 | irqreturn_t(*irq_handler) (DRM_IRQ_ARGS); | 602 | irqreturn_t(*irq_handler) (DRM_IRQ_ARGS); |
| 643 | void (*irq_preinstall) (struct drm_device *dev); | 603 | void (*irq_preinstall) (struct drm_device *dev); |
| 644 | int (*irq_postinstall) (struct drm_device *dev); | 604 | void (*irq_postinstall) (struct drm_device *dev); |
| 645 | void (*irq_uninstall) (struct drm_device *dev); | 605 | void (*irq_uninstall) (struct drm_device *dev); |
| 646 | void (*reclaim_buffers) (struct drm_device *dev, | 606 | void (*reclaim_buffers) (struct drm_device *dev, |
| 647 | struct drm_file * file_priv); | 607 | struct drm_file * file_priv); |
| @@ -770,21 +730,13 @@ struct drm_device { | |||
| 770 | /** \name VBLANK IRQ support */ | 730 | /** \name VBLANK IRQ support */ |
| 771 | /*@{ */ | 731 | /*@{ */ |
| 772 | 732 | ||
| 773 | wait_queue_head_t *vbl_queue; /**< VBLANK wait queue */ | 733 | wait_queue_head_t vbl_queue; /**< VBLANK wait queue */ |
| 774 | atomic_t *_vblank_count; /**< number of VBLANK interrupts (driver must alloc the right number of counters) */ | 734 | atomic_t vbl_received; |
| 735 | atomic_t vbl_received2; /**< number of secondary VBLANK interrupts */ | ||
| 775 | spinlock_t vbl_lock; | 736 | spinlock_t vbl_lock; |
| 776 | struct list_head *vbl_sigs; /**< signal list to send on VBLANK */ | 737 | struct list_head vbl_sigs; /**< signal list to send on VBLANK */ |
| 777 | atomic_t vbl_signal_pending; /* number of signals pending on all crtcs*/ | 738 | struct list_head vbl_sigs2; /**< signals to send on secondary VBLANK */ |
| 778 | atomic_t *vblank_refcount; /* number of users of vblank interrupts per crtc */ | 739 | unsigned int vbl_pending; |
| 779 | u32 *last_vblank; /* protected by dev->vbl_lock, used */ | ||
| 780 | /* for wraparound handling */ | ||
| 781 | u32 *vblank_offset; /* used to track how many vblanks */ | ||
| 782 | int *vblank_enabled; /* so we don't call enable more than | ||
| 783 | once per disable */ | ||
| 784 | u32 *vblank_premodeset; /* were lost during modeset */ | ||
| 785 | struct timer_list vblank_disable_timer; | ||
| 786 | |||
| 787 | unsigned long max_vblank_count; /**< size of vblank counter register */ | ||
| 788 | spinlock_t tasklet_lock; /**< For drm_locked_tasklet */ | 740 | spinlock_t tasklet_lock; /**< For drm_locked_tasklet */ |
| 789 | void (*locked_tasklet_func)(struct drm_device *dev); | 741 | void (*locked_tasklet_func)(struct drm_device *dev); |
| 790 | 742 | ||
| @@ -804,7 +756,6 @@ struct drm_device { | |||
| 804 | #ifdef __alpha__ | 756 | #ifdef __alpha__ |
| 805 | struct pci_controller *hose; | 757 | struct pci_controller *hose; |
| 806 | #endif | 758 | #endif |
| 807 | int num_crtcs; /**< Number of CRTCs on this device */ | ||
| 808 | struct drm_sg_mem *sg; /**< Scatter gather memory */ | 759 | struct drm_sg_mem *sg; /**< Scatter gather memory */ |
| 809 | void *dev_private; /**< device private data */ | 760 | void *dev_private; /**< device private data */ |
| 810 | struct drm_sigdata sigdata; /**< For block_all_signals */ | 761 | struct drm_sigdata sigdata; /**< For block_all_signals */ |
| @@ -1039,19 +990,11 @@ extern void drm_driver_irq_preinstall(struct drm_device *dev); | |||
| 1039 | extern void drm_driver_irq_postinstall(struct drm_device *dev); | 990 | extern void drm_driver_irq_postinstall(struct drm_device *dev); |
| 1040 | extern void drm_driver_irq_uninstall(struct drm_device *dev); | 991 | extern void drm_driver_irq_uninstall(struct drm_device *dev); |
| 1041 | 992 | ||
| 1042 | extern int drm_vblank_init(struct drm_device *dev, int num_crtcs); | 993 | extern int drm_wait_vblank(struct drm_device *dev, void *data, |
| 1043 | extern int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *filp); | ||
| 1044 | extern int drm_vblank_wait(struct drm_device * dev, unsigned int *vbl_seq); | ||
| 1045 | extern void drm_locked_tasklet(struct drm_device *dev, void(*func)(struct drm_device*)); | ||
| 1046 | extern u32 drm_vblank_count(struct drm_device *dev, int crtc); | ||
| 1047 | extern void drm_update_vblank_count(struct drm_device *dev, int crtc); | ||
| 1048 | extern void drm_handle_vblank(struct drm_device *dev, int crtc); | ||
| 1049 | extern int drm_vblank_get(struct drm_device *dev, int crtc); | ||
| 1050 | extern void drm_vblank_put(struct drm_device *dev, int crtc); | ||
| 1051 | |||
| 1052 | /* Modesetting support */ | ||
| 1053 | extern int drm_modeset_ctl(struct drm_device *dev, void *data, | ||
| 1054 | struct drm_file *file_priv); | 994 | struct drm_file *file_priv); |
| 995 | extern int drm_vblank_wait(struct drm_device *dev, unsigned int *vbl_seq); | ||
| 996 | extern void drm_vbl_send_signals(struct drm_device *dev); | ||
| 997 | extern void drm_locked_tasklet(struct drm_device *dev, void(*func)(struct drm_device*)); | ||
| 1055 | 998 | ||
| 1056 | /* AGP/GART support (drm_agpsupport.h) */ | 999 | /* AGP/GART support (drm_agpsupport.h) */ |
| 1057 | extern struct drm_agp_head *drm_agp_init(struct drm_device *dev); | 1000 | extern struct drm_agp_head *drm_agp_init(struct drm_device *dev); |
diff --git a/drivers/char/drm/drm_fops.c b/drivers/char/drm/drm_fops.c index 68f0da801ed..d2e6da85f58 100644 --- a/drivers/char/drm/drm_fops.c +++ b/drivers/char/drm/drm_fops.c | |||
| @@ -323,7 +323,6 @@ int drm_release(struct inode *inode, struct file *filp) | |||
| 323 | struct drm_file *file_priv = filp->private_data; | 323 | struct drm_file *file_priv = filp->private_data; |
| 324 | struct drm_device *dev = file_priv->minor->dev; | 324 | struct drm_device *dev = file_priv->minor->dev; |
| 325 | int retcode = 0; | 325 | int retcode = 0; |
| 326 | unsigned long irqflags; | ||
| 327 | 326 | ||
| 328 | lock_kernel(); | 327 | lock_kernel(); |
| 329 | 328 | ||
| @@ -355,11 +354,9 @@ int drm_release(struct inode *inode, struct file *filp) | |||
| 355 | */ | 354 | */ |
| 356 | 355 | ||
| 357 | do{ | 356 | do{ |
| 358 | spin_lock_irqsave(&dev->lock.spinlock, | 357 | spin_lock_bh(&dev->lock.spinlock); |
| 359 | irqflags); | ||
| 360 | locked = dev->lock.idle_has_lock; | 358 | locked = dev->lock.idle_has_lock; |
| 361 | spin_unlock_irqrestore(&dev->lock.spinlock, | 359 | spin_unlock_bh(&dev->lock.spinlock); |
| 362 | irqflags); | ||
| 363 | if (locked) | 360 | if (locked) |
| 364 | break; | 361 | break; |
| 365 | schedule(); | 362 | schedule(); |
diff --git a/drivers/char/drm/drm_irq.c b/drivers/char/drm/drm_irq.c index 286f9d61e7d..089c015c01d 100644 --- a/drivers/char/drm/drm_irq.c +++ b/drivers/char/drm/drm_irq.c | |||
| @@ -71,117 +71,6 @@ 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 | for (i = 0; i < dev->num_crtcs; i++) { | ||
| 81 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | ||
| 82 | if (atomic_read(&dev->vblank_refcount[i]) == 0 && | ||
| 83 | dev->vblank_enabled[i]) { | ||
| 84 | dev->driver->disable_vblank(dev, i); | ||
| 85 | dev->vblank_enabled[i] = 0; | ||
| 86 | } | ||
| 87 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | static void drm_vblank_cleanup(struct drm_device *dev) | ||
| 92 | { | ||
| 93 | /* Bail if the driver didn't call drm_vblank_init() */ | ||
| 94 | if (dev->num_crtcs == 0) | ||
| 95 | return; | ||
| 96 | |||
| 97 | del_timer(&dev->vblank_disable_timer); | ||
| 98 | |||
| 99 | vblank_disable_fn((unsigned long)dev); | ||
| 100 | |||
| 101 | drm_free(dev->vbl_queue, sizeof(*dev->vbl_queue) * dev->num_crtcs, | ||
| 102 | DRM_MEM_DRIVER); | ||
| 103 | drm_free(dev->vbl_sigs, sizeof(*dev->vbl_sigs) * dev->num_crtcs, | ||
| 104 | DRM_MEM_DRIVER); | ||
| 105 | drm_free(dev->_vblank_count, sizeof(*dev->_vblank_count) * | ||
| 106 | dev->num_crtcs, DRM_MEM_DRIVER); | ||
| 107 | drm_free(dev->vblank_refcount, sizeof(*dev->vblank_refcount) * | ||
| 108 | dev->num_crtcs, DRM_MEM_DRIVER); | ||
| 109 | drm_free(dev->vblank_enabled, sizeof(*dev->vblank_enabled) * | ||
| 110 | dev->num_crtcs, DRM_MEM_DRIVER); | ||
| 111 | drm_free(dev->last_vblank, sizeof(*dev->last_vblank) * dev->num_crtcs, | ||
| 112 | DRM_MEM_DRIVER); | ||
| 113 | drm_free(dev->vblank_premodeset, sizeof(*dev->vblank_premodeset) * | ||
| 114 | dev->num_crtcs, DRM_MEM_DRIVER); | ||
| 115 | drm_free(dev->vblank_offset, sizeof(*dev->vblank_offset) * dev->num_crtcs, | ||
| 116 | DRM_MEM_DRIVER); | ||
| 117 | |||
| 118 | dev->num_crtcs = 0; | ||
| 119 | } | ||
| 120 | |||
| 121 | int drm_vblank_init(struct drm_device *dev, int num_crtcs) | ||
| 122 | { | ||
| 123 | int i, ret = -ENOMEM; | ||
| 124 | |||
| 125 | setup_timer(&dev->vblank_disable_timer, vblank_disable_fn, | ||
| 126 | (unsigned long)dev); | ||
| 127 | spin_lock_init(&dev->vbl_lock); | ||
| 128 | atomic_set(&dev->vbl_signal_pending, 0); | ||
| 129 | dev->num_crtcs = num_crtcs; | ||
| 130 | |||
| 131 | dev->vbl_queue = drm_alloc(sizeof(wait_queue_head_t) * num_crtcs, | ||
| 132 | DRM_MEM_DRIVER); | ||
| 133 | if (!dev->vbl_queue) | ||
| 134 | goto err; | ||
| 135 | |||
| 136 | dev->vbl_sigs = drm_alloc(sizeof(struct list_head) * num_crtcs, | ||
| 137 | DRM_MEM_DRIVER); | ||
| 138 | if (!dev->vbl_sigs) | ||
| 139 | goto err; | ||
| 140 | |||
| 141 | dev->_vblank_count = drm_alloc(sizeof(atomic_t) * num_crtcs, | ||
| 142 | DRM_MEM_DRIVER); | ||
| 143 | if (!dev->_vblank_count) | ||
| 144 | goto err; | ||
| 145 | |||
| 146 | dev->vblank_refcount = drm_alloc(sizeof(atomic_t) * num_crtcs, | ||
| 147 | DRM_MEM_DRIVER); | ||
| 148 | if (!dev->vblank_refcount) | ||
| 149 | goto err; | ||
| 150 | |||
| 151 | dev->vblank_enabled = drm_calloc(num_crtcs, sizeof(int), | ||
| 152 | DRM_MEM_DRIVER); | ||
| 153 | if (!dev->vblank_enabled) | ||
| 154 | goto err; | ||
| 155 | |||
| 156 | dev->last_vblank = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER); | ||
| 157 | if (!dev->last_vblank) | ||
| 158 | goto err; | ||
| 159 | |||
| 160 | dev->vblank_premodeset = drm_calloc(num_crtcs, sizeof(u32), | ||
| 161 | DRM_MEM_DRIVER); | ||
| 162 | if (!dev->vblank_premodeset) | ||
| 163 | goto err; | ||
| 164 | |||
| 165 | dev->vblank_offset = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER); | ||
| 166 | if (!dev->vblank_offset) | ||
| 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 | return 0; | ||
| 178 | |||
| 179 | err: | ||
| 180 | drm_vblank_cleanup(dev); | ||
| 181 | return ret; | ||
| 182 | } | ||
| 183 | EXPORT_SYMBOL(drm_vblank_init); | ||
| 184 | |||
| 185 | /** | 74 | /** |
| 186 | * Install IRQ handler. | 75 | * Install IRQ handler. |
| 187 | * | 76 | * |
| @@ -220,6 +109,17 @@ static int drm_irq_install(struct drm_device * dev) | |||
| 220 | 109 | ||
| 221 | DRM_DEBUG("irq=%d\n", dev->irq); | 110 | DRM_DEBUG("irq=%d\n", dev->irq); |
| 222 | 111 | ||
| 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 | |||
| 223 | /* Before installing handler */ | 123 | /* Before installing handler */ |
| 224 | dev->driver->irq_preinstall(dev); | 124 | dev->driver->irq_preinstall(dev); |
| 225 | 125 | ||
| @@ -237,14 +137,9 @@ static int drm_irq_install(struct drm_device * dev) | |||
| 237 | } | 137 | } |
| 238 | 138 | ||
| 239 | /* After installing handler */ | 139 | /* After installing handler */ |
| 240 | ret = dev->driver->irq_postinstall(dev); | 140 | dev->driver->irq_postinstall(dev); |
| 241 | if (ret < 0) { | ||
| 242 | mutex_lock(&dev->struct_mutex); | ||
| 243 | dev->irq_enabled = 0; | ||
| 244 | mutex_unlock(&dev->struct_mutex); | ||
| 245 | } | ||
| 246 | 141 | ||
| 247 | return ret; | 142 | return 0; |
| 248 | } | 143 | } |
| 249 | 144 | ||
| 250 | /** | 145 | /** |
| @@ -275,8 +170,6 @@ int drm_irq_uninstall(struct drm_device * dev) | |||
| 275 | 170 | ||
| 276 | free_irq(dev->irq, dev); | 171 | free_irq(dev->irq, dev); |
| 277 | 172 | ||
| 278 | drm_vblank_cleanup(dev); | ||
| 279 | |||
| 280 | dev->locked_tasklet_func = NULL; | 173 | dev->locked_tasklet_func = NULL; |
| 281 | 174 | ||
| 282 | return 0; | 175 | return 0; |
| @@ -321,148 +214,6 @@ int drm_control(struct drm_device *dev, void *data, | |||
| 321 | } | 214 | } |
| 322 | 215 | ||
| 323 | /** | 216 | /** |
| 324 | * drm_vblank_count - retrieve "cooked" vblank counter value | ||
| 325 | * @dev: DRM device | ||
| 326 | * @crtc: which counter to retrieve | ||
| 327 | * | ||
| 328 | * Fetches the "cooked" vblank count value that represents the number of | ||
| 329 | * vblank events since the system was booted, including lost events due to | ||
| 330 | * modesetting activity. | ||
| 331 | */ | ||
| 332 | u32 drm_vblank_count(struct drm_device *dev, int crtc) | ||
| 333 | { | ||
| 334 | return atomic_read(&dev->_vblank_count[crtc]) + | ||
| 335 | dev->vblank_offset[crtc]; | ||
| 336 | } | ||
| 337 | EXPORT_SYMBOL(drm_vblank_count); | ||
| 338 | |||
| 339 | /** | ||
| 340 | * drm_update_vblank_count - update the master vblank counter | ||
| 341 | * @dev: DRM device | ||
| 342 | * @crtc: counter to update | ||
| 343 | * | ||
| 344 | * Call back into the driver to update the appropriate vblank counter | ||
| 345 | * (specified by @crtc). Deal with wraparound, if it occurred, and | ||
| 346 | * update the last read value so we can deal with wraparound on the next | ||
| 347 | * call if necessary. | ||
| 348 | */ | ||
| 349 | void drm_update_vblank_count(struct drm_device *dev, int crtc) | ||
| 350 | { | ||
| 351 | unsigned long irqflags; | ||
| 352 | u32 cur_vblank, diff; | ||
| 353 | |||
| 354 | /* | ||
| 355 | * Interrupts were disabled prior to this call, so deal with counter | ||
| 356 | * wrap if needed. | ||
| 357 | * NOTE! It's possible we lost a full dev->max_vblank_count events | ||
| 358 | * here if the register is small or we had vblank interrupts off for | ||
| 359 | * a long time. | ||
| 360 | */ | ||
| 361 | cur_vblank = dev->driver->get_vblank_counter(dev, crtc); | ||
| 362 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | ||
| 363 | if (cur_vblank < dev->last_vblank[crtc]) { | ||
| 364 | diff = dev->max_vblank_count - | ||
| 365 | dev->last_vblank[crtc]; | ||
| 366 | diff += cur_vblank; | ||
| 367 | } else { | ||
| 368 | diff = cur_vblank - dev->last_vblank[crtc]; | ||
| 369 | } | ||
| 370 | dev->last_vblank[crtc] = cur_vblank; | ||
| 371 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | ||
| 372 | |||
| 373 | atomic_add(diff, &dev->_vblank_count[crtc]); | ||
| 374 | } | ||
| 375 | EXPORT_SYMBOL(drm_update_vblank_count); | ||
| 376 | |||
| 377 | /** | ||
| 378 | * drm_vblank_get - get a reference count on vblank events | ||
| 379 | * @dev: DRM device | ||
| 380 | * @crtc: which CRTC to own | ||
| 381 | * | ||
| 382 | * Acquire a reference count on vblank events to avoid having them disabled | ||
| 383 | * while in use. Note callers will probably want to update the master counter | ||
| 384 | * using drm_update_vblank_count() above before calling this routine so that | ||
| 385 | * wakeups occur on the right vblank event. | ||
| 386 | * | ||
| 387 | * RETURNS | ||
| 388 | * Zero on success, nonzero on failure. | ||
| 389 | */ | ||
| 390 | int drm_vblank_get(struct drm_device *dev, int crtc) | ||
| 391 | { | ||
| 392 | unsigned long irqflags; | ||
| 393 | int ret = 0; | ||
| 394 | |||
| 395 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | ||
| 396 | /* Going from 0->1 means we have to enable interrupts again */ | ||
| 397 | if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1 && | ||
| 398 | !dev->vblank_enabled[crtc]) { | ||
| 399 | ret = dev->driver->enable_vblank(dev, crtc); | ||
| 400 | if (ret) | ||
| 401 | atomic_dec(&dev->vblank_refcount[crtc]); | ||
| 402 | else | ||
| 403 | dev->vblank_enabled[crtc] = 1; | ||
| 404 | } | ||
| 405 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | ||
| 406 | |||
| 407 | return ret; | ||
| 408 | } | ||
| 409 | EXPORT_SYMBOL(drm_vblank_get); | ||
| 410 | |||
| 411 | /** | ||
| 412 | * drm_vblank_put - give up ownership of vblank events | ||
| 413 | * @dev: DRM device | ||
| 414 | * @crtc: which counter to give up | ||
| 415 | * | ||
| 416 | * Release ownership of a given vblank counter, turning off interrupts | ||
| 417 | * if possible. | ||
| 418 | */ | ||
| 419 | void drm_vblank_put(struct drm_device *dev, int crtc) | ||
| 420 | { | ||
| 421 | /* Last user schedules interrupt disable */ | ||
| 422 | if (atomic_dec_and_test(&dev->vblank_refcount[crtc])) | ||
| 423 | mod_timer(&dev->vblank_disable_timer, jiffies + 5*DRM_HZ); | ||
| 424 | } | ||
| 425 | EXPORT_SYMBOL(drm_vblank_put); | ||
| 426 | |||
| 427 | /** | ||
| 428 | * drm_modeset_ctl - handle vblank event counter changes across mode switch | ||
| 429 | * @DRM_IOCTL_ARGS: standard ioctl arguments | ||
| 430 | * | ||
| 431 | * Applications should call the %_DRM_PRE_MODESET and %_DRM_POST_MODESET | ||
| 432 | * ioctls around modesetting so that any lost vblank events are accounted for. | ||
| 433 | */ | ||
| 434 | int drm_modeset_ctl(struct drm_device *dev, void *data, | ||
| 435 | struct drm_file *file_priv) | ||
| 436 | { | ||
| 437 | struct drm_modeset_ctl *modeset = data; | ||
| 438 | int crtc, ret = 0; | ||
| 439 | u32 new; | ||
| 440 | |||
| 441 | crtc = modeset->arg; | ||
| 442 | if (crtc >= dev->num_crtcs) { | ||
| 443 | ret = -EINVAL; | ||
| 444 | goto out; | ||
| 445 | } | ||
| 446 | |||
| 447 | switch (modeset->cmd) { | ||
| 448 | case _DRM_PRE_MODESET: | ||
| 449 | dev->vblank_premodeset[crtc] = | ||
| 450 | dev->driver->get_vblank_counter(dev, crtc); | ||
| 451 | break; | ||
| 452 | case _DRM_POST_MODESET: | ||
| 453 | new = dev->driver->get_vblank_counter(dev, crtc); | ||
| 454 | dev->vblank_offset[crtc] = dev->vblank_premodeset[crtc] - new; | ||
| 455 | break; | ||
| 456 | default: | ||
| 457 | ret = -EINVAL; | ||
| 458 | break; | ||
| 459 | } | ||
| 460 | |||
| 461 | out: | ||
| 462 | return ret; | ||
| 463 | } | ||
| 464 | |||
| 465 | /** | ||
| 466 | * Wait for VBLANK. | 217 | * Wait for VBLANK. |
| 467 | * | 218 | * |
| 468 | * \param inode device inode. | 219 | * \param inode device inode. |
| @@ -481,13 +232,12 @@ out: | |||
| 481 | * | 232 | * |
| 482 | * If a signal is not requested, then calls vblank_wait(). | 233 | * If a signal is not requested, then calls vblank_wait(). |
| 483 | */ | 234 | */ |
| 484 | int drm_wait_vblank(struct drm_device *dev, void *data, | 235 | int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv) |
| 485 | struct drm_file *file_priv) | ||
| 486 | { | 236 | { |
| 487 | union drm_wait_vblank *vblwait = data; | 237 | union drm_wait_vblank *vblwait = data; |
| 488 | struct timeval now; | 238 | struct timeval now; |
| 489 | int ret = 0; | 239 | int ret = 0; |
| 490 | unsigned int flags, seq, crtc; | 240 | unsigned int flags, seq; |
| 491 | 241 | ||
| 492 | if ((!dev->irq) || (!dev->irq_enabled)) | 242 | if ((!dev->irq) || (!dev->irq_enabled)) |
| 493 | return -EINVAL; | 243 | return -EINVAL; |
| @@ -501,13 +251,13 @@ int drm_wait_vblank(struct drm_device *dev, void *data, | |||
| 501 | } | 251 | } |
| 502 | 252 | ||
| 503 | flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK; | 253 | flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK; |
| 504 | crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0; | ||
| 505 | 254 | ||
| 506 | if (crtc >= dev->num_crtcs) | 255 | if (!drm_core_check_feature(dev, (flags & _DRM_VBLANK_SECONDARY) ? |
| 256 | DRIVER_IRQ_VBL2 : DRIVER_IRQ_VBL)) | ||
| 507 | return -EINVAL; | 257 | return -EINVAL; |
| 508 | 258 | ||
| 509 | drm_update_vblank_count(dev, crtc); | 259 | seq = atomic_read((flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2 |
| 510 | seq = drm_vblank_count(dev, crtc); | 260 | : &dev->vbl_received); |
| 511 | 261 | ||
| 512 | switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) { | 262 | switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) { |
| 513 | case _DRM_VBLANK_RELATIVE: | 263 | case _DRM_VBLANK_RELATIVE: |
| @@ -526,7 +276,8 @@ int drm_wait_vblank(struct drm_device *dev, void *data, | |||
| 526 | 276 | ||
| 527 | if (flags & _DRM_VBLANK_SIGNAL) { | 277 | if (flags & _DRM_VBLANK_SIGNAL) { |
| 528 | unsigned long irqflags; | 278 | unsigned long irqflags; |
| 529 | struct list_head *vbl_sigs = &dev->vbl_sigs[crtc]; | 279 | struct list_head *vbl_sigs = (flags & _DRM_VBLANK_SECONDARY) |
| 280 | ? &dev->vbl_sigs2 : &dev->vbl_sigs; | ||
| 530 | struct drm_vbl_sig *vbl_sig; | 281 | struct drm_vbl_sig *vbl_sig; |
| 531 | 282 | ||
| 532 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | 283 | spin_lock_irqsave(&dev->vbl_lock, irqflags); |
| @@ -547,26 +298,22 @@ int drm_wait_vblank(struct drm_device *dev, void *data, | |||
| 547 | } | 298 | } |
| 548 | } | 299 | } |
| 549 | 300 | ||
| 550 | if (atomic_read(&dev->vbl_signal_pending) >= 100) { | 301 | if (dev->vbl_pending >= 100) { |
| 551 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | 302 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); |
| 552 | return -EBUSY; | 303 | return -EBUSY; |
| 553 | } | 304 | } |
| 554 | 305 | ||
| 306 | dev->vbl_pending++; | ||
| 307 | |||
| 555 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | 308 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); |
| 556 | 309 | ||
| 557 | vbl_sig = drm_calloc(1, sizeof(struct drm_vbl_sig), | 310 | if (! |
| 558 | DRM_MEM_DRIVER); | 311 | (vbl_sig = |
| 559 | if (!vbl_sig) | 312 | drm_alloc(sizeof(struct drm_vbl_sig), DRM_MEM_DRIVER))) { |
| 560 | return -ENOMEM; | 313 | return -ENOMEM; |
| 561 | |||
| 562 | ret = drm_vblank_get(dev, crtc); | ||
| 563 | if (ret) { | ||
| 564 | drm_free(vbl_sig, sizeof(struct drm_vbl_sig), | ||
| 565 | DRM_MEM_DRIVER); | ||
| 566 | return ret; | ||
| 567 | } | 314 | } |
| 568 | 315 | ||
| 569 | atomic_inc(&dev->vbl_signal_pending); | 316 | memset((void *)vbl_sig, 0, sizeof(*vbl_sig)); |
| 570 | 317 | ||
| 571 | vbl_sig->sequence = vblwait->request.sequence; | 318 | vbl_sig->sequence = vblwait->request.sequence; |
| 572 | vbl_sig->info.si_signo = vblwait->request.signal; | 319 | vbl_sig->info.si_signo = vblwait->request.signal; |
| @@ -580,20 +327,17 @@ int drm_wait_vblank(struct drm_device *dev, void *data, | |||
| 580 | 327 | ||
| 581 | vblwait->reply.sequence = seq; | 328 | vblwait->reply.sequence = seq; |
| 582 | } else { | 329 | } else { |
| 583 | unsigned long cur_vblank; | 330 | if (flags & _DRM_VBLANK_SECONDARY) { |
| 584 | 331 | if (dev->driver->vblank_wait2) | |
| 585 | ret = drm_vblank_get(dev, crtc); | 332 | ret = dev->driver->vblank_wait2(dev, &vblwait->request.sequence); |
| 586 | if (ret) | 333 | } else if (dev->driver->vblank_wait) |
| 587 | return ret; | 334 | ret = |
| 588 | DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ, | 335 | dev->driver->vblank_wait(dev, |
| 589 | (((cur_vblank = drm_vblank_count(dev, crtc)) | 336 | &vblwait->request.sequence); |
| 590 | - vblwait->request.sequence) <= (1 << 23))); | ||
| 591 | drm_vblank_put(dev, crtc); | ||
| 592 | do_gettimeofday(&now); | ||
| 593 | 337 | ||
| 338 | do_gettimeofday(&now); | ||
| 594 | vblwait->reply.tval_sec = now.tv_sec; | 339 | vblwait->reply.tval_sec = now.tv_sec; |
| 595 | vblwait->reply.tval_usec = now.tv_usec; | 340 | vblwait->reply.tval_usec = now.tv_usec; |
| 596 | vblwait->reply.sequence = cur_vblank; | ||
| 597 | } | 341 | } |
| 598 | 342 | ||
| 599 | done: | 343 | done: |
| @@ -604,57 +348,44 @@ int drm_wait_vblank(struct drm_device *dev, void *data, | |||
| 604 | * Send the VBLANK signals. | 348 | * Send the VBLANK signals. |
| 605 | * | 349 | * |
| 606 | * \param dev DRM device. | 350 | * \param dev DRM device. |
| 607 | * \param crtc CRTC where the vblank event occurred | ||
| 608 | * | 351 | * |
| 609 | * Sends a signal for each task in drm_device::vbl_sigs and empties the list. | 352 | * Sends a signal for each task in drm_device::vbl_sigs and empties the list. |
| 610 | * | 353 | * |
| 611 | * If a signal is not requested, then calls vblank_wait(). | 354 | * If a signal is not requested, then calls vblank_wait(). |
| 612 | */ | 355 | */ |
| 613 | static void drm_vbl_send_signals(struct drm_device * dev, int crtc) | 356 | void drm_vbl_send_signals(struct drm_device * dev) |
| 614 | { | 357 | { |
| 615 | struct drm_vbl_sig *vbl_sig, *tmp; | ||
| 616 | struct list_head *vbl_sigs; | ||
| 617 | unsigned int vbl_seq; | ||
| 618 | unsigned long flags; | 358 | unsigned long flags; |
| 359 | int i; | ||
| 619 | 360 | ||
| 620 | spin_lock_irqsave(&dev->vbl_lock, flags); | 361 | spin_lock_irqsave(&dev->vbl_lock, flags); |
| 621 | 362 | ||
| 622 | vbl_sigs = &dev->vbl_sigs[crtc]; | 363 | for (i = 0; i < 2; i++) { |
| 623 | vbl_seq = drm_vblank_count(dev, crtc); | 364 | struct drm_vbl_sig *vbl_sig, *tmp; |
| 365 | struct list_head *vbl_sigs = i ? &dev->vbl_sigs2 : &dev->vbl_sigs; | ||
| 366 | unsigned int vbl_seq = atomic_read(i ? &dev->vbl_received2 : | ||
| 367 | &dev->vbl_received); | ||
| 624 | 368 | ||
| 625 | list_for_each_entry_safe(vbl_sig, tmp, vbl_sigs, head) { | 369 | list_for_each_entry_safe(vbl_sig, tmp, vbl_sigs, head) { |
| 626 | if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) { | 370 | if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) { |
| 627 | vbl_sig->info.si_code = vbl_seq; | 371 | vbl_sig->info.si_code = vbl_seq; |
| 628 | send_sig_info(vbl_sig->info.si_signo, | 372 | send_sig_info(vbl_sig->info.si_signo, |
| 629 | &vbl_sig->info, vbl_sig->task); | 373 | &vbl_sig->info, vbl_sig->task); |
| 630 | 374 | ||
| 631 | list_del(&vbl_sig->head); | 375 | list_del(&vbl_sig->head); |
| 632 | 376 | ||
| 633 | drm_free(vbl_sig, sizeof(*vbl_sig), | 377 | drm_free(vbl_sig, sizeof(*vbl_sig), |
| 634 | DRM_MEM_DRIVER); | 378 | DRM_MEM_DRIVER); |
| 635 | atomic_dec(&dev->vbl_signal_pending); | 379 | |
| 636 | drm_vblank_put(dev, crtc); | 380 | dev->vbl_pending--; |
| 637 | } | 381 | } |
| 382 | } | ||
| 638 | } | 383 | } |
| 639 | 384 | ||
| 640 | spin_unlock_irqrestore(&dev->vbl_lock, flags); | 385 | spin_unlock_irqrestore(&dev->vbl_lock, flags); |
| 641 | } | 386 | } |
| 642 | 387 | ||
| 643 | /** | 388 | EXPORT_SYMBOL(drm_vbl_send_signals); |
| 644 | * drm_handle_vblank - handle a vblank event | ||
| 645 | * @dev: DRM device | ||
| 646 | * @crtc: where this event occurred | ||
| 647 | * | ||
| 648 | * Drivers should call this routine in their vblank interrupt handlers to | ||
| 649 | * update the vblank counter and send any signals that may be pending. | ||
| 650 | */ | ||
| 651 | void drm_handle_vblank(struct drm_device *dev, int crtc) | ||
| 652 | { | ||
| 653 | drm_update_vblank_count(dev, crtc); | ||
| 654 | DRM_WAKEUP(&dev->vbl_queue[crtc]); | ||
| 655 | drm_vbl_send_signals(dev, crtc); | ||
| 656 | } | ||
| 657 | EXPORT_SYMBOL(drm_handle_vblank); | ||
| 658 | 389 | ||
| 659 | /** | 390 | /** |
| 660 | * Tasklet wrapper function. | 391 | * Tasklet wrapper function. |
diff --git a/drivers/char/drm/drm_lock.c b/drivers/char/drm/drm_lock.c index 12dcdd1832f..0998723cde7 100644 --- a/drivers/char/drm/drm_lock.c +++ b/drivers/char/drm/drm_lock.c | |||
| @@ -53,7 +53,6 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) | |||
| 53 | DECLARE_WAITQUEUE(entry, current); | 53 | DECLARE_WAITQUEUE(entry, current); |
| 54 | struct drm_lock *lock = data; | 54 | struct drm_lock *lock = data; |
| 55 | int ret = 0; | 55 | int ret = 0; |
| 56 | unsigned long irqflags; | ||
| 57 | 56 | ||
| 58 | ++file_priv->lock_count; | 57 | ++file_priv->lock_count; |
| 59 | 58 | ||
| @@ -72,9 +71,9 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) | |||
| 72 | return -EINVAL; | 71 | return -EINVAL; |
| 73 | 72 | ||
| 74 | add_wait_queue(&dev->lock.lock_queue, &entry); | 73 | add_wait_queue(&dev->lock.lock_queue, &entry); |
| 75 | spin_lock_irqsave(&dev->lock.spinlock, irqflags); | 74 | spin_lock_bh(&dev->lock.spinlock); |
| 76 | dev->lock.user_waiters++; | 75 | dev->lock.user_waiters++; |
| 77 | spin_unlock_irqrestore(&dev->lock.spinlock, irqflags); | 76 | spin_unlock_bh(&dev->lock.spinlock); |
| 78 | for (;;) { | 77 | for (;;) { |
| 79 | __set_current_state(TASK_INTERRUPTIBLE); | 78 | __set_current_state(TASK_INTERRUPTIBLE); |
| 80 | if (!dev->lock.hw_lock) { | 79 | if (!dev->lock.hw_lock) { |
| @@ -96,9 +95,9 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) | |||
| 96 | break; | 95 | break; |
| 97 | } | 96 | } |
| 98 | } | 97 | } |
| 99 | spin_lock_irqsave(&dev->lock.spinlock, irqflags); | 98 | spin_lock_bh(&dev->lock.spinlock); |
| 100 | dev->lock.user_waiters--; | 99 | dev->lock.user_waiters--; |
| 101 | spin_unlock_irqrestore(&dev->lock.spinlock, irqflags); | 100 | spin_unlock_bh(&dev->lock.spinlock); |
| 102 | __set_current_state(TASK_RUNNING); | 101 | __set_current_state(TASK_RUNNING); |
| 103 | remove_wait_queue(&dev->lock.lock_queue, &entry); | 102 | remove_wait_queue(&dev->lock.lock_queue, &entry); |
| 104 | 103 | ||
| @@ -199,9 +198,8 @@ int drm_lock_take(struct drm_lock_data *lock_data, | |||
| 199 | { | 198 | { |
| 200 | unsigned int old, new, prev; | 199 | unsigned int old, new, prev; |
| 201 | volatile unsigned int *lock = &lock_data->hw_lock->lock; | 200 | volatile unsigned int *lock = &lock_data->hw_lock->lock; |
| 202 | unsigned long irqflags; | ||
| 203 | 201 | ||
| 204 | spin_lock_irqsave(&lock_data->spinlock, irqflags); | 202 | spin_lock_bh(&lock_data->spinlock); |
| 205 | do { | 203 | do { |
| 206 | old = *lock; | 204 | old = *lock; |
| 207 | if (old & _DRM_LOCK_HELD) | 205 | if (old & _DRM_LOCK_HELD) |
| @@ -213,7 +211,7 @@ int drm_lock_take(struct drm_lock_data *lock_data, | |||
| 213 | } | 211 | } |
| 214 | prev = cmpxchg(lock, old, new); | 212 | prev = cmpxchg(lock, old, new); |
| 215 | } while (prev != old); | 213 | } while (prev != old); |
| 216 | spin_unlock_irqrestore(&lock_data->spinlock, irqflags); | 214 | spin_unlock_bh(&lock_data->spinlock); |
| 217 | 215 | ||
| 218 | if (_DRM_LOCKING_CONTEXT(old) == context) { | 216 | if (_DRM_LOCKING_CONTEXT(old) == context) { |
| 219 | if (old & _DRM_LOCK_HELD) { | 217 | if (old & _DRM_LOCK_HELD) { |
| @@ -274,16 +272,15 @@ int drm_lock_free(struct drm_lock_data *lock_data, unsigned int context) | |||
| 274 | { | 272 | { |
| 275 | unsigned int old, new, prev; | 273 | unsigned int old, new, prev; |
| 276 | volatile unsigned int *lock = &lock_data->hw_lock->lock; | 274 | volatile unsigned int *lock = &lock_data->hw_lock->lock; |
| 277 | unsigned long irqflags; | ||
| 278 | 275 | ||
| 279 | spin_lock_irqsave(&lock_data->spinlock, irqflags); | 276 | spin_lock_bh(&lock_data->spinlock); |
| 280 | if (lock_data->kernel_waiters != 0) { | 277 | if (lock_data->kernel_waiters != 0) { |
| 281 | drm_lock_transfer(lock_data, 0); | 278 | drm_lock_transfer(lock_data, 0); |
| 282 | lock_data->idle_has_lock = 1; | 279 | lock_data->idle_has_lock = 1; |
| 283 | spin_unlock_irqrestore(&lock_data->spinlock, irqflags); | 280 | spin_unlock_bh(&lock_data->spinlock); |
| 284 | return 1; | 281 | return 1; |
| 285 | } | 282 | } |
| 286 | spin_unlock_irqrestore(&lock_data->spinlock, irqflags); | 283 | spin_unlock_bh(&lock_data->spinlock); |
| 287 | 284 | ||
| 288 | do { | 285 | do { |
| 289 | old = *lock; | 286 | old = *lock; |
| @@ -347,20 +344,19 @@ static int drm_notifier(void *priv) | |||
| 347 | void drm_idlelock_take(struct drm_lock_data *lock_data) | 344 | void drm_idlelock_take(struct drm_lock_data *lock_data) |
| 348 | { | 345 | { |
| 349 | int ret = 0; | 346 | int ret = 0; |
| 350 | unsigned long irqflags; | ||
| 351 | 347 | ||
| 352 | spin_lock_irqsave(&lock_data->spinlock, irqflags); | 348 | spin_lock_bh(&lock_data->spinlock); |
| 353 | lock_data->kernel_waiters++; | 349 | lock_data->kernel_waiters++; |
| 354 | if (!lock_data->idle_has_lock) { | 350 | if (!lock_data->idle_has_lock) { |
| 355 | 351 | ||
| 356 | spin_unlock_irqrestore(&lock_data->spinlock, irqflags); | 352 | spin_unlock_bh(&lock_data->spinlock); |
| 357 | ret = drm_lock_take(lock_data, DRM_KERNEL_CONTEXT); | 353 | ret = drm_lock_take(lock_data, DRM_KERNEL_CONTEXT); |
| 358 | spin_lock_irqsave(&lock_data->spinlock, irqflags); | 354 | spin_lock_bh(&lock_data->spinlock); |
| 359 | 355 | ||
| 360 | if (ret == 1) | 356 | if (ret == 1) |
| 361 | lock_data->idle_has_lock = 1; | 357 | lock_data->idle_has_lock = 1; |
| 362 | } | 358 | } |
| 363 | spin_unlock_irqrestore(&lock_data->spinlock, irqflags); | 359 | spin_unlock_bh(&lock_data->spinlock); |
| 364 | } | 360 | } |
| 365 | EXPORT_SYMBOL(drm_idlelock_take); | 361 | EXPORT_SYMBOL(drm_idlelock_take); |
| 366 | 362 | ||
| @@ -368,9 +364,8 @@ void drm_idlelock_release(struct drm_lock_data *lock_data) | |||
| 368 | { | 364 | { |
| 369 | unsigned int old, prev; | 365 | unsigned int old, prev; |
| 370 | volatile unsigned int *lock = &lock_data->hw_lock->lock; | 366 | volatile unsigned int *lock = &lock_data->hw_lock->lock; |
| 371 | unsigned long irqflags; | ||
| 372 | 367 | ||
| 373 | spin_lock_irqsave(&lock_data->spinlock, irqflags); | 368 | spin_lock_bh(&lock_data->spinlock); |
| 374 | if (--lock_data->kernel_waiters == 0) { | 369 | if (--lock_data->kernel_waiters == 0) { |
| 375 | if (lock_data->idle_has_lock) { | 370 | if (lock_data->idle_has_lock) { |
| 376 | do { | 371 | do { |
| @@ -381,7 +376,7 @@ void drm_idlelock_release(struct drm_lock_data *lock_data) | |||
| 381 | lock_data->idle_has_lock = 0; | 376 | lock_data->idle_has_lock = 0; |
| 382 | } | 377 | } |
| 383 | } | 378 | } |
| 384 | spin_unlock_irqrestore(&lock_data->spinlock, irqflags); | 379 | spin_unlock_bh(&lock_data->spinlock); |
| 385 | } | 380 | } |
| 386 | EXPORT_SYMBOL(drm_idlelock_release); | 381 | EXPORT_SYMBOL(drm_idlelock_release); |
| 387 | 382 | ||
diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c index f47e46e3529..88974342933 100644 --- a/drivers/char/drm/i915_dma.c +++ b/drivers/char/drm/i915_dma.c | |||
| @@ -415,13 +415,10 @@ static void i915_emit_breadcrumb(struct drm_device *dev) | |||
| 415 | drm_i915_private_t *dev_priv = dev->dev_private; | 415 | drm_i915_private_t *dev_priv = dev->dev_private; |
| 416 | RING_LOCALS; | 416 | RING_LOCALS; |
| 417 | 417 | ||
| 418 | if (++dev_priv->counter > BREADCRUMB_MASK) { | 418 | dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter; |
| 419 | dev_priv->counter = 1; | ||
| 420 | DRM_DEBUG("Breadcrumb counter wrapped around\n"); | ||
| 421 | } | ||
| 422 | 419 | ||
| 423 | if (dev_priv->sarea_priv) | 420 | if (dev_priv->counter > 0x7FFFFFFFUL) |
| 424 | dev_priv->sarea_priv->last_enqueue = dev_priv->counter; | 421 | dev_priv->sarea_priv->last_enqueue = dev_priv->counter = 1; |
| 425 | 422 | ||
| 426 | BEGIN_LP_RING(4); | 423 | BEGIN_LP_RING(4); |
| 427 | OUT_RING(CMD_STORE_DWORD_IDX); | 424 | OUT_RING(CMD_STORE_DWORD_IDX); |
| @@ -431,26 +428,6 @@ static void i915_emit_breadcrumb(struct drm_device *dev) | |||
| 431 | ADVANCE_LP_RING(); | 428 | ADVANCE_LP_RING(); |
| 432 | } | 429 | } |
| 433 | 430 | ||
| 434 | int i915_emit_mi_flush(struct drm_device *dev, uint32_t flush) | ||
| 435 | { | ||
| 436 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
| 437 | uint32_t flush_cmd = CMD_MI_FLUSH; | ||
| 438 | RING_LOCALS; | ||
| 439 | |||
| 440 | flush_cmd |= flush; | ||
| 441 | |||
| 442 | i915_kernel_lost_context(dev); | ||
| 443 | |||
| 444 | BEGIN_LP_RING(4); | ||
| 445 | OUT_RING(flush_cmd); | ||
| 446 | OUT_RING(0); | ||
| 447 | OUT_RING(0); | ||
| 448 | OUT_RING(0); | ||
| 449 | ADVANCE_LP_RING(); | ||
| 450 | |||
| 451 | return 0; | ||
| 452 | } | ||
| 453 | |||
| 454 | static int i915_dispatch_cmdbuffer(struct drm_device * dev, | 431 | static int i915_dispatch_cmdbuffer(struct drm_device * dev, |
| 455 | drm_i915_cmdbuffer_t * cmd) | 432 | drm_i915_cmdbuffer_t * cmd) |
| 456 | { | 433 | { |
| @@ -534,74 +511,52 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev, | |||
| 534 | return 0; | 511 | return 0; |
| 535 | } | 512 | } |
| 536 | 513 | ||
| 537 | static void i915_do_dispatch_flip(struct drm_device * dev, int plane, int sync) | 514 | static int i915_dispatch_flip(struct drm_device * dev) |
| 538 | { | 515 | { |
| 539 | drm_i915_private_t *dev_priv = dev->dev_private; | 516 | drm_i915_private_t *dev_priv = dev->dev_private; |
| 540 | u32 num_pages, current_page, next_page, dspbase; | ||
| 541 | int shift = 2 * plane, x, y; | ||
| 542 | RING_LOCALS; | 517 | RING_LOCALS; |
| 543 | 518 | ||
| 544 | /* Calculate display base offset */ | 519 | DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n", |
| 545 | num_pages = dev_priv->sarea_priv->third_handle ? 3 : 2; | 520 | __FUNCTION__, |
| 546 | current_page = (dev_priv->sarea_priv->pf_current_page >> shift) & 0x3; | 521 | dev_priv->current_page, |
| 547 | next_page = (current_page + 1) % num_pages; | 522 | dev_priv->sarea_priv->pf_current_page); |
| 548 | 523 | ||
| 549 | switch (next_page) { | 524 | i915_kernel_lost_context(dev); |
| 550 | default: | 525 | |
| 551 | case 0: | 526 | BEGIN_LP_RING(2); |
| 552 | dspbase = dev_priv->sarea_priv->front_offset; | 527 | OUT_RING(INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE); |
| 553 | break; | 528 | OUT_RING(0); |
| 554 | case 1: | 529 | ADVANCE_LP_RING(); |
| 555 | dspbase = dev_priv->sarea_priv->back_offset; | ||
| 556 | break; | ||
| 557 | case 2: | ||
| 558 | dspbase = dev_priv->sarea_priv->third_offset; | ||
| 559 | break; | ||
| 560 | } | ||
| 561 | 530 | ||
| 562 | if (plane == 0) { | 531 | BEGIN_LP_RING(6); |
| 563 | x = dev_priv->sarea_priv->planeA_x; | 532 | OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | ASYNC_FLIP); |
| 564 | y = dev_priv->sarea_priv->planeA_y; | 533 | OUT_RING(0); |
| 534 | if (dev_priv->current_page == 0) { | ||
| 535 | OUT_RING(dev_priv->back_offset); | ||
| 536 | dev_priv->current_page = 1; | ||
| 565 | } else { | 537 | } else { |
| 566 | x = dev_priv->sarea_priv->planeB_x; | 538 | OUT_RING(dev_priv->front_offset); |
| 567 | y = dev_priv->sarea_priv->planeB_y; | 539 | dev_priv->current_page = 0; |
| 568 | } | 540 | } |
| 541 | OUT_RING(0); | ||
| 542 | ADVANCE_LP_RING(); | ||
| 569 | 543 | ||
| 570 | dspbase += (y * dev_priv->sarea_priv->pitch + x) * dev_priv->cpp; | 544 | BEGIN_LP_RING(2); |
| 545 | OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_A_FLIP); | ||
| 546 | OUT_RING(0); | ||
| 547 | ADVANCE_LP_RING(); | ||
| 571 | 548 | ||
| 572 | DRM_DEBUG("plane=%d current_page=%d dspbase=0x%x\n", plane, current_page, | 549 | dev_priv->sarea_priv->last_enqueue = dev_priv->counter++; |
| 573 | dspbase); | ||
| 574 | 550 | ||
| 575 | BEGIN_LP_RING(4); | 551 | BEGIN_LP_RING(4); |
| 576 | OUT_RING(sync ? 0 : | 552 | OUT_RING(CMD_STORE_DWORD_IDX); |
| 577 | (MI_WAIT_FOR_EVENT | (plane ? MI_WAIT_FOR_PLANE_B_FLIP : | 553 | OUT_RING(20); |
| 578 | MI_WAIT_FOR_PLANE_A_FLIP))); | 554 | OUT_RING(dev_priv->counter); |
| 579 | OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | (sync ? 0 : ASYNC_FLIP) | | 555 | OUT_RING(0); |
| 580 | (plane ? DISPLAY_PLANE_B : DISPLAY_PLANE_A)); | ||
| 581 | OUT_RING(dev_priv->sarea_priv->pitch * dev_priv->cpp); | ||
| 582 | OUT_RING(dspbase); | ||
| 583 | ADVANCE_LP_RING(); | 556 | ADVANCE_LP_RING(); |
| 584 | 557 | ||
| 585 | dev_priv->sarea_priv->pf_current_page &= ~(0x3 << shift); | 558 | dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; |
| 586 | dev_priv->sarea_priv->pf_current_page |= next_page << shift; | 559 | return 0; |
| 587 | } | ||
| 588 | |||
| 589 | void i915_dispatch_flip(struct drm_device * dev, int planes, int sync) | ||
| 590 | { | ||
| 591 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
| 592 | int i; | ||
| 593 | |||
| 594 | DRM_DEBUG("planes=0x%x pfCurrentPage=%d\n", | ||
| 595 | planes, dev_priv->sarea_priv->pf_current_page); | ||
| 596 | |||
| 597 | i915_emit_mi_flush(dev, MI_READ_FLUSH | MI_EXE_FLUSH); | ||
| 598 | |||
| 599 | for (i = 0; i < 2; i++) | ||
| 600 | if (planes & (1 << i)) | ||
| 601 | i915_do_dispatch_flip(dev, i, sync); | ||
| 602 | |||
| 603 | i915_emit_breadcrumb(dev); | ||
| 604 | |||
| 605 | } | 560 | } |
| 606 | 561 | ||
| 607 | static int i915_quiescent(struct drm_device * dev) | 562 | static int i915_quiescent(struct drm_device * dev) |
| @@ -624,6 +579,7 @@ static int i915_batchbuffer(struct drm_device *dev, void *data, | |||
| 624 | struct drm_file *file_priv) | 579 | struct drm_file *file_priv) |
| 625 | { | 580 | { |
| 626 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 581 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
| 582 | u32 *hw_status = dev_priv->hw_status_page; | ||
| 627 | drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) | 583 | drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) |
| 628 | dev_priv->sarea_priv; | 584 | dev_priv->sarea_priv; |
| 629 | drm_i915_batchbuffer_t *batch = data; | 585 | drm_i915_batchbuffer_t *batch = data; |
| @@ -646,7 +602,7 @@ static int i915_batchbuffer(struct drm_device *dev, void *data, | |||
| 646 | 602 | ||
| 647 | ret = i915_dispatch_batchbuffer(dev, batch); | 603 | ret = i915_dispatch_batchbuffer(dev, batch); |
| 648 | 604 | ||
| 649 | sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); | 605 | sarea_priv->last_dispatch = (int)hw_status[5]; |
| 650 | return ret; | 606 | return ret; |
| 651 | } | 607 | } |
| 652 | 608 | ||
| @@ -654,6 +610,7 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data, | |||
| 654 | struct drm_file *file_priv) | 610 | struct drm_file *file_priv) |
| 655 | { | 611 | { |
| 656 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 612 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
| 613 | u32 *hw_status = dev_priv->hw_status_page; | ||
| 657 | drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) | 614 | drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) |
| 658 | dev_priv->sarea_priv; | 615 | dev_priv->sarea_priv; |
| 659 | drm_i915_cmdbuffer_t *cmdbuf = data; | 616 | drm_i915_cmdbuffer_t *cmdbuf = data; |
| @@ -678,51 +635,18 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data, | |||
| 678 | return ret; | 635 | return ret; |
| 679 | } | 636 | } |
| 680 | 637 | ||
| 681 | sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); | 638 | sarea_priv->last_dispatch = (int)hw_status[5]; |
| 682 | return 0; | ||
| 683 | } | ||
| 684 | |||
| 685 | static int i915_do_cleanup_pageflip(struct drm_device * dev) | ||
| 686 | { | ||
| 687 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
| 688 | int i, planes, num_pages = dev_priv->sarea_priv->third_handle ? 3 : 2; | ||
| 689 | |||
| 690 | DRM_DEBUG("\n"); | ||
| 691 | |||
| 692 | for (i = 0, planes = 0; i < 2; i++) | ||
| 693 | if (dev_priv->sarea_priv->pf_current_page & (0x3 << (2 * i))) { | ||
| 694 | dev_priv->sarea_priv->pf_current_page = | ||
| 695 | (dev_priv->sarea_priv->pf_current_page & | ||
| 696 | ~(0x3 << (2 * i))) | ((num_pages - 1) << (2 * i)); | ||
| 697 | |||
| 698 | planes |= 1 << i; | ||
| 699 | } | ||
| 700 | |||
| 701 | if (planes) | ||
| 702 | i915_dispatch_flip(dev, planes, 0); | ||
| 703 | |||
| 704 | return 0; | 639 | return 0; |
| 705 | } | 640 | } |
| 706 | 641 | ||
| 707 | static int i915_flip_bufs(struct drm_device *dev, void *data, | 642 | static int i915_flip_bufs(struct drm_device *dev, void *data, |
| 708 | struct drm_file *file_priv) | 643 | struct drm_file *file_priv) |
| 709 | { | 644 | { |
| 710 | drm_i915_flip_t *param = data; | 645 | DRM_DEBUG("%s\n", __FUNCTION__); |
| 711 | |||
| 712 | DRM_DEBUG("\n"); | ||
| 713 | 646 | ||
| 714 | LOCK_TEST_WITH_RETURN(dev, file_priv); | 647 | LOCK_TEST_WITH_RETURN(dev, file_priv); |
| 715 | 648 | ||
| 716 | /* This is really planes */ | 649 | return i915_dispatch_flip(dev); |
| 717 | if (param->pipes & ~0x3) { | ||
| 718 | DRM_ERROR("Invalid planes 0x%x, only <= 0x3 is valid\n", | ||
| 719 | param->pipes); | ||
| 720 | return -EINVAL; | ||
| 721 | } | ||
| 722 | |||
| 723 | i915_dispatch_flip(dev, param->pipes, 0); | ||
| 724 | |||
| 725 | return 0; | ||
| 726 | } | 650 | } |
| 727 | 651 | ||
| 728 | static int i915_getparam(struct drm_device *dev, void *data, | 652 | static int i915_getparam(struct drm_device *dev, void *data, |
| @@ -883,8 +807,6 @@ void i915_driver_lastclose(struct drm_device * dev) | |||
| 883 | if (!dev_priv) | 807 | if (!dev_priv) |
| 884 | return; | 808 | return; |
| 885 | 809 | ||
| 886 | if (drm_getsarea(dev) && dev_priv->sarea_priv) | ||
| 887 | i915_do_cleanup_pageflip(dev); | ||
| 888 | if (dev_priv->agp_heap) | 810 | if (dev_priv->agp_heap) |
| 889 | i915_mem_takedown(&(dev_priv->agp_heap)); | 811 | i915_mem_takedown(&(dev_priv->agp_heap)); |
| 890 | 812 | ||
diff --git a/drivers/char/drm/i915_drm.h b/drivers/char/drm/i915_drm.h index 0431c00e228..05c66cf03a9 100644 --- a/drivers/char/drm/i915_drm.h +++ b/drivers/char/drm/i915_drm.h | |||
| @@ -105,29 +105,14 @@ typedef struct _drm_i915_sarea { | |||
| 105 | unsigned int rotated_tiled; | 105 | unsigned int rotated_tiled; |
| 106 | unsigned int rotated2_tiled; | 106 | unsigned int rotated2_tiled; |
| 107 | 107 | ||
| 108 | int planeA_x; | 108 | int pipeA_x; |
| 109 | int planeA_y; | 109 | int pipeA_y; |
| 110 | int planeA_w; | 110 | int pipeA_w; |
| 111 | int planeA_h; | 111 | int pipeA_h; |
| 112 | int planeB_x; | 112 | int pipeB_x; |
| 113 | int planeB_y; | 113 | int pipeB_y; |
| 114 | int planeB_w; | 114 | int pipeB_w; |
| 115 | int planeB_h; | 115 | int pipeB_h; |
| 116 | |||
| 117 | /* Triple buffering */ | ||
| 118 | drm_handle_t third_handle; | ||
| 119 | int third_offset; | ||
| 120 | int third_size; | ||
| 121 | unsigned int third_tiled; | ||
| 122 | |||
| 123 | /* buffer object handles for the static buffers. May change | ||
| 124 | * over the lifetime of the client, though it doesn't in our current | ||
| 125 | * implementation. | ||
| 126 | */ | ||
| 127 | unsigned int front_bo_handle; | ||
| 128 | unsigned int back_bo_handle; | ||
| 129 | unsigned int third_bo_handle; | ||
| 130 | unsigned int depth_bo_handle; | ||
| 131 | } drm_i915_sarea_t; | 116 | } drm_i915_sarea_t; |
| 132 | 117 | ||
| 133 | /* Flags for perf_boxes | 118 | /* Flags for perf_boxes |
| @@ -161,7 +146,7 @@ typedef struct _drm_i915_sarea { | |||
| 161 | 146 | ||
| 162 | #define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t) | 147 | #define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t) |
| 163 | #define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH) | 148 | #define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH) |
| 164 | #define DRM_IOCTL_I915_FLIP DRM_IOW( DRM_COMMAND_BASE + DRM_I915_FLIP, drm_i915_flip_t) | 149 | #define DRM_IOCTL_I915_FLIP DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLIP) |
| 165 | #define DRM_IOCTL_I915_BATCHBUFFER DRM_IOW( DRM_COMMAND_BASE + DRM_I915_BATCHBUFFER, drm_i915_batchbuffer_t) | 150 | #define DRM_IOCTL_I915_BATCHBUFFER DRM_IOW( DRM_COMMAND_BASE + DRM_I915_BATCHBUFFER, drm_i915_batchbuffer_t) |
| 166 | #define DRM_IOCTL_I915_IRQ_EMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_IRQ_EMIT, drm_i915_irq_emit_t) | 151 | #define DRM_IOCTL_I915_IRQ_EMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_IRQ_EMIT, drm_i915_irq_emit_t) |
| 167 | #define DRM_IOCTL_I915_IRQ_WAIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_IRQ_WAIT, drm_i915_irq_wait_t) | 152 | #define DRM_IOCTL_I915_IRQ_WAIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_IRQ_WAIT, drm_i915_irq_wait_t) |
| @@ -176,18 +161,6 @@ typedef struct _drm_i915_sarea { | |||
| 176 | #define DRM_IOCTL_I915_GET_VBLANK_PIPE DRM_IOR( DRM_COMMAND_BASE + DRM_I915_GET_VBLANK_PIPE, drm_i915_vblank_pipe_t) | 161 | #define DRM_IOCTL_I915_GET_VBLANK_PIPE DRM_IOR( DRM_COMMAND_BASE + DRM_I915_GET_VBLANK_PIPE, drm_i915_vblank_pipe_t) |
| 177 | #define DRM_IOCTL_I915_VBLANK_SWAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_VBLANK_SWAP, drm_i915_vblank_swap_t) | 162 | #define DRM_IOCTL_I915_VBLANK_SWAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_VBLANK_SWAP, drm_i915_vblank_swap_t) |
| 178 | 163 | ||
| 179 | /* Asynchronous page flipping: | ||
| 180 | */ | ||
| 181 | typedef struct drm_i915_flip { | ||
| 182 | /* | ||
| 183 | * This is really talking about planes, and we could rename it | ||
| 184 | * except for the fact that some of the duplicated i915_drm.h files | ||
| 185 | * out there check for HAVE_I915_FLIP and so might pick up this | ||
| 186 | * version. | ||
| 187 | */ | ||
| 188 | int pipes; | ||
| 189 | } drm_i915_flip_t; | ||
| 190 | |||
| 191 | /* Allow drivers to submit batchbuffers directly to hardware, relying | 164 | /* Allow drivers to submit batchbuffers directly to hardware, relying |
| 192 | * on the security mechanisms provided by hardware. | 165 | * on the security mechanisms provided by hardware. |
| 193 | */ | 166 | */ |
diff --git a/drivers/char/drm/i915_drv.c b/drivers/char/drm/i915_drv.c index bb8f1b2fb38..e8f3d682e3b 100644 --- a/drivers/char/drm/i915_drv.c +++ b/drivers/char/drm/i915_drv.c | |||
| @@ -147,7 +147,7 @@ static void i915_save_vga(struct drm_device *dev) | |||
| 147 | i915_write_indexed(cr_index, cr_data, 0x11, | 147 | i915_write_indexed(cr_index, cr_data, 0x11, |
| 148 | i915_read_indexed(cr_index, cr_data, 0x11) & | 148 | i915_read_indexed(cr_index, cr_data, 0x11) & |
| 149 | (~0x80)); | 149 | (~0x80)); |
| 150 | for (i = 0; i < 0x24; i++) | 150 | for (i = 0; i <= 0x24; i++) |
| 151 | dev_priv->saveCR[i] = | 151 | dev_priv->saveCR[i] = |
| 152 | i915_read_indexed(cr_index, cr_data, i); | 152 | i915_read_indexed(cr_index, cr_data, i); |
| 153 | /* Make sure we don't turn off CR group 0 writes */ | 153 | /* Make sure we don't turn off CR group 0 writes */ |
| @@ -156,7 +156,7 @@ static void i915_save_vga(struct drm_device *dev) | |||
| 156 | /* Attribute controller registers */ | 156 | /* Attribute controller registers */ |
| 157 | inb(st01); | 157 | inb(st01); |
| 158 | dev_priv->saveAR_INDEX = inb(VGA_AR_INDEX); | 158 | dev_priv->saveAR_INDEX = inb(VGA_AR_INDEX); |
| 159 | for (i = 0; i < 20; i++) | 159 | for (i = 0; i <= 0x14; i++) |
| 160 | dev_priv->saveAR[i] = i915_read_ar(st01, i, 0); | 160 | dev_priv->saveAR[i] = i915_read_ar(st01, i, 0); |
| 161 | inb(st01); | 161 | inb(st01); |
| 162 | outb(dev_priv->saveAR_INDEX, VGA_AR_INDEX); | 162 | outb(dev_priv->saveAR_INDEX, VGA_AR_INDEX); |
| @@ -206,7 +206,7 @@ static void i915_restore_vga(struct drm_device *dev) | |||
| 206 | /* CRT controller regs */ | 206 | /* CRT controller regs */ |
| 207 | /* Enable CR group 0 writes */ | 207 | /* Enable CR group 0 writes */ |
| 208 | i915_write_indexed(cr_index, cr_data, 0x11, dev_priv->saveCR[0x11]); | 208 | i915_write_indexed(cr_index, cr_data, 0x11, dev_priv->saveCR[0x11]); |
| 209 | for (i = 0; i < 0x24; i++) | 209 | for (i = 0; i <= 0x24; i++) |
| 210 | i915_write_indexed(cr_index, cr_data, i, dev_priv->saveCR[i]); | 210 | i915_write_indexed(cr_index, cr_data, i, dev_priv->saveCR[i]); |
| 211 | 211 | ||
| 212 | /* Graphics controller regs */ | 212 | /* Graphics controller regs */ |
| @@ -223,7 +223,7 @@ static void i915_restore_vga(struct drm_device *dev) | |||
| 223 | 223 | ||
| 224 | /* Attribute controller registers */ | 224 | /* Attribute controller registers */ |
| 225 | inb(st01); | 225 | inb(st01); |
| 226 | for (i = 0; i < 20; i++) | 226 | for (i = 0; i <= 0x14; i++) |
| 227 | i915_write_ar(st01, i, dev_priv->saveAR[i], 0); | 227 | i915_write_ar(st01, i, dev_priv->saveAR[i], 0); |
| 228 | inb(st01); /* switch back to index mode */ | 228 | inb(st01); /* switch back to index mode */ |
| 229 | outb(dev_priv->saveAR_INDEX | 0x20, VGA_AR_INDEX); | 229 | outb(dev_priv->saveAR_INDEX | 0x20, VGA_AR_INDEX); |
| @@ -256,6 +256,9 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state) | |||
| 256 | pci_save_state(dev->pdev); | 256 | pci_save_state(dev->pdev); |
| 257 | pci_read_config_byte(dev->pdev, LBB, &dev_priv->saveLBB); | 257 | pci_read_config_byte(dev->pdev, LBB, &dev_priv->saveLBB); |
| 258 | 258 | ||
| 259 | /* Display arbitration control */ | ||
| 260 | dev_priv->saveDSPARB = I915_READ(DSPARB); | ||
| 261 | |||
| 259 | /* Pipe & plane A info */ | 262 | /* Pipe & plane A info */ |
| 260 | dev_priv->savePIPEACONF = I915_READ(PIPEACONF); | 263 | dev_priv->savePIPEACONF = I915_READ(PIPEACONF); |
| 261 | dev_priv->savePIPEASRC = I915_READ(PIPEASRC); | 264 | dev_priv->savePIPEASRC = I915_READ(PIPEASRC); |
| @@ -349,6 +352,7 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state) | |||
| 349 | dev_priv->saveVGACNTRL = I915_READ(VGACNTRL); | 352 | dev_priv->saveVGACNTRL = I915_READ(VGACNTRL); |
| 350 | 353 | ||
| 351 | /* Clock gating state */ | 354 | /* Clock gating state */ |
| 355 | dev_priv->saveD_STATE = I915_READ(D_STATE); | ||
| 352 | dev_priv->saveDSPCLK_GATE_D = I915_READ(DSPCLK_GATE_D); | 356 | dev_priv->saveDSPCLK_GATE_D = I915_READ(DSPCLK_GATE_D); |
| 353 | 357 | ||
| 354 | /* Cache mode state */ | 358 | /* Cache mode state */ |
| @@ -388,6 +392,8 @@ static int i915_resume(struct drm_device *dev) | |||
| 388 | 392 | ||
| 389 | pci_write_config_byte(dev->pdev, LBB, dev_priv->saveLBB); | 393 | pci_write_config_byte(dev->pdev, LBB, dev_priv->saveLBB); |
| 390 | 394 | ||
| 395 | I915_WRITE(DSPARB, dev_priv->saveDSPARB); | ||
| 396 | |||
| 391 | /* Pipe & plane A info */ | 397 | /* Pipe & plane A info */ |
| 392 | /* Prime the clock */ | 398 | /* Prime the clock */ |
| 393 | if (dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) { | 399 | if (dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) { |
| @@ -507,6 +513,7 @@ static int i915_resume(struct drm_device *dev) | |||
| 507 | udelay(150); | 513 | udelay(150); |
| 508 | 514 | ||
| 509 | /* Clock gating state */ | 515 | /* Clock gating state */ |
| 516 | I915_WRITE (D_STATE, dev_priv->saveD_STATE); | ||
| 510 | I915_WRITE (DSPCLK_GATE_D, dev_priv->saveDSPCLK_GATE_D); | 517 | I915_WRITE (DSPCLK_GATE_D, dev_priv->saveDSPCLK_GATE_D); |
| 511 | 518 | ||
| 512 | /* Cache mode state */ | 519 | /* Cache mode state */ |
| @@ -533,7 +540,8 @@ static struct drm_driver driver = { | |||
| 533 | */ | 540 | */ |
| 534 | .driver_features = | 541 | .driver_features = |
| 535 | DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | /* DRIVER_USE_MTRR |*/ | 542 | DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | /* DRIVER_USE_MTRR |*/ |
| 536 | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED, | 543 | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL | |
| 544 | DRIVER_IRQ_VBL2, | ||
| 537 | .load = i915_driver_load, | 545 | .load = i915_driver_load, |
| 538 | .unload = i915_driver_unload, | 546 | .unload = i915_driver_unload, |
| 539 | .lastclose = i915_driver_lastclose, | 547 | .lastclose = i915_driver_lastclose, |
| @@ -541,9 +549,8 @@ static struct drm_driver driver = { | |||
| 541 | .suspend = i915_suspend, | 549 | .suspend = i915_suspend, |
| 542 | .resume = i915_resume, | 550 | .resume = i915_resume, |
| 543 | .device_is_agp = i915_driver_device_is_agp, | 551 | .device_is_agp = i915_driver_device_is_agp, |
| 544 | .get_vblank_counter = i915_get_vblank_counter, | 552 | .vblank_wait = i915_driver_vblank_wait, |
| 545 | .enable_vblank = i915_enable_vblank, | 553 | .vblank_wait2 = i915_driver_vblank_wait2, |
| 546 | .disable_vblank = i915_disable_vblank, | ||
| 547 | .irq_preinstall = i915_driver_irq_preinstall, | 554 | .irq_preinstall = i915_driver_irq_preinstall, |
| 548 | .irq_postinstall = i915_driver_irq_postinstall, | 555 | .irq_postinstall = i915_driver_irq_postinstall, |
| 549 | .irq_uninstall = i915_driver_irq_uninstall, | 556 | .irq_uninstall = i915_driver_irq_uninstall, |
diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h index db7001f2256..1b20f7c0639 100644 --- a/drivers/char/drm/i915_drv.h +++ b/drivers/char/drm/i915_drv.h | |||
| @@ -76,9 +76,8 @@ struct mem_block { | |||
| 76 | typedef struct _drm_i915_vbl_swap { | 76 | typedef struct _drm_i915_vbl_swap { |
| 77 | struct list_head head; | 77 | struct list_head head; |
| 78 | drm_drawable_t drw_id; | 78 | drm_drawable_t drw_id; |
| 79 | unsigned int plane; | 79 | unsigned int pipe; |
| 80 | unsigned int sequence; | 80 | unsigned int sequence; |
| 81 | int flip; | ||
| 82 | } drm_i915_vbl_swap_t; | 81 | } drm_i915_vbl_swap_t; |
| 83 | 82 | ||
| 84 | typedef struct drm_i915_private { | 83 | typedef struct drm_i915_private { |
| @@ -91,7 +90,7 @@ typedef struct drm_i915_private { | |||
| 91 | drm_dma_handle_t *status_page_dmah; | 90 | drm_dma_handle_t *status_page_dmah; |
| 92 | void *hw_status_page; | 91 | void *hw_status_page; |
| 93 | dma_addr_t dma_status_page; | 92 | dma_addr_t dma_status_page; |
| 94 | uint32_t counter; | 93 | unsigned long counter; |
| 95 | unsigned int status_gfx_addr; | 94 | unsigned int status_gfx_addr; |
| 96 | drm_local_map_t hws_map; | 95 | drm_local_map_t hws_map; |
| 97 | 96 | ||
| @@ -104,18 +103,13 @@ typedef struct drm_i915_private { | |||
| 104 | 103 | ||
| 105 | wait_queue_head_t irq_queue; | 104 | wait_queue_head_t irq_queue; |
| 106 | atomic_t irq_received; | 105 | atomic_t irq_received; |
| 107 | atomic_t irq_emited; | 106 | atomic_t irq_emitted; |
| 108 | 107 | ||
| 109 | int tex_lru_log_granularity; | 108 | int tex_lru_log_granularity; |
| 110 | int allow_batchbuffer; | 109 | int allow_batchbuffer; |
| 111 | struct mem_block *agp_heap; | 110 | struct mem_block *agp_heap; |
| 112 | unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds; | 111 | unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds; |
| 113 | int vblank_pipe; | 112 | int vblank_pipe; |
| 114 | spinlock_t user_irq_lock; | ||
| 115 | int user_irq_refcount; | ||
| 116 | int fence_irq_on; | ||
| 117 | uint32_t irq_enable_reg; | ||
| 118 | int irq_enabled; | ||
| 119 | 113 | ||
| 120 | spinlock_t swaps_lock; | 114 | spinlock_t swaps_lock; |
| 121 | drm_i915_vbl_swap_t vbl_swaps; | 115 | drm_i915_vbl_swap_t vbl_swaps; |
| @@ -125,6 +119,7 @@ typedef struct drm_i915_private { | |||
| 125 | u8 saveLBB; | 119 | u8 saveLBB; |
| 126 | u32 saveDSPACNTR; | 120 | u32 saveDSPACNTR; |
| 127 | u32 saveDSPBCNTR; | 121 | u32 saveDSPBCNTR; |
| 122 | u32 saveDSPARB; | ||
| 128 | u32 savePIPEACONF; | 123 | u32 savePIPEACONF; |
| 129 | u32 savePIPEBCONF; | 124 | u32 savePIPEBCONF; |
| 130 | u32 savePIPEASRC; | 125 | u32 savePIPEASRC; |
| @@ -194,6 +189,7 @@ typedef struct drm_i915_private { | |||
| 194 | u32 saveIIR; | 189 | u32 saveIIR; |
| 195 | u32 saveIMR; | 190 | u32 saveIMR; |
| 196 | u32 saveCACHE_MODE_0; | 191 | u32 saveCACHE_MODE_0; |
| 192 | u32 saveD_STATE; | ||
| 197 | u32 saveDSPCLK_GATE_D; | 193 | u32 saveDSPCLK_GATE_D; |
| 198 | u32 saveMI_ARB_STATE; | 194 | u32 saveMI_ARB_STATE; |
| 199 | u32 saveSWF0[16]; | 195 | u32 saveSWF0[16]; |
| @@ -203,10 +199,10 @@ typedef struct drm_i915_private { | |||
| 203 | u8 saveSR[8]; | 199 | u8 saveSR[8]; |
| 204 | u8 saveGR[25]; | 200 | u8 saveGR[25]; |
| 205 | u8 saveAR_INDEX; | 201 | u8 saveAR_INDEX; |
| 206 | u8 saveAR[20]; | 202 | u8 saveAR[21]; |
| 207 | u8 saveDACMASK; | 203 | u8 saveDACMASK; |
| 208 | u8 saveDACDATA[256*3]; /* 256 3-byte colors */ | 204 | u8 saveDACDATA[256*3]; /* 256 3-byte colors */ |
| 209 | u8 saveCR[36]; | 205 | u8 saveCR[37]; |
| 210 | } drm_i915_private_t; | 206 | } drm_i915_private_t; |
| 211 | 207 | ||
| 212 | extern struct drm_ioctl_desc i915_ioctls[]; | 208 | extern struct drm_ioctl_desc i915_ioctls[]; |
| @@ -222,7 +218,7 @@ extern void i915_driver_preclose(struct drm_device *dev, | |||
| 222 | extern int i915_driver_device_is_agp(struct drm_device * dev); | 218 | extern int i915_driver_device_is_agp(struct drm_device * dev); |
| 223 | extern long i915_compat_ioctl(struct file *filp, unsigned int cmd, | 219 | extern long i915_compat_ioctl(struct file *filp, unsigned int cmd, |
| 224 | unsigned long arg); | 220 | unsigned long arg); |
| 225 | extern void i915_dispatch_flip(struct drm_device * dev, int pipes, int sync); | 221 | |
| 226 | /* i915_irq.c */ | 222 | /* i915_irq.c */ |
| 227 | extern int i915_irq_emit(struct drm_device *dev, void *data, | 223 | extern int i915_irq_emit(struct drm_device *dev, void *data, |
| 228 | struct drm_file *file_priv); | 224 | struct drm_file *file_priv); |
| @@ -233,7 +229,7 @@ extern int i915_driver_vblank_wait(struct drm_device *dev, unsigned int *sequenc | |||
| 233 | extern int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence); | 229 | extern int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence); |
| 234 | extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS); | 230 | extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS); |
| 235 | extern void i915_driver_irq_preinstall(struct drm_device * dev); | 231 | extern void i915_driver_irq_preinstall(struct drm_device * dev); |
| 236 | extern int i915_driver_irq_postinstall(struct drm_device * dev); | 232 | extern void i915_driver_irq_postinstall(struct drm_device * dev); |
| 237 | extern void i915_driver_irq_uninstall(struct drm_device * dev); | 233 | extern void i915_driver_irq_uninstall(struct drm_device * dev); |
| 238 | extern int i915_vblank_pipe_set(struct drm_device *dev, void *data, | 234 | extern int i915_vblank_pipe_set(struct drm_device *dev, void *data, |
| 239 | struct drm_file *file_priv); | 235 | struct drm_file *file_priv); |
| @@ -241,9 +237,6 @@ extern int i915_vblank_pipe_get(struct drm_device *dev, void *data, | |||
| 241 | struct drm_file *file_priv); | 237 | struct drm_file *file_priv); |
| 242 | extern int i915_vblank_swap(struct drm_device *dev, void *data, | 238 | extern int i915_vblank_swap(struct drm_device *dev, void *data, |
| 243 | struct drm_file *file_priv); | 239 | struct drm_file *file_priv); |
| 244 | extern int i915_enable_vblank(struct drm_device *dev, int crtc); | ||
| 245 | extern void i915_disable_vblank(struct drm_device *dev, int crtc); | ||
| 246 | extern u32 i915_get_vblank_counter(struct drm_device *dev, int crtc); | ||
| 247 | 240 | ||
| 248 | /* i915_mem.c */ | 241 | /* i915_mem.c */ |
| 249 | extern int i915_mem_alloc(struct drm_device *dev, void *data, | 242 | extern int i915_mem_alloc(struct drm_device *dev, void *data, |
| @@ -388,91 +381,21 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); | |||
| 388 | 381 | ||
| 389 | /* Interrupt bits: | 382 | /* Interrupt bits: |
| 390 | */ | 383 | */ |
| 391 | #define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1<<18) | 384 | #define USER_INT_FLAG (1<<1) |
| 392 | #define I915_DISPLAY_PORT_INTERRUPT (1<<17) | 385 | #define VSYNC_PIPEB_FLAG (1<<5) |
| 393 | #define I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT (1<<15) | 386 | #define VSYNC_PIPEA_FLAG (1<<7) |
| 394 | #define I915_GMCH_THERMAL_SENSOR_EVENT_INTERRUPT (1<<14) | 387 | #define HWB_OOM_FLAG (1<<13) /* binner out of memory */ |
| 395 | #define I915_HWB_OOM_INTERRUPT (1<<13) /* binner out of memory */ | ||
| 396 | #define I915_SYNC_STATUS_INTERRUPT (1<<12) | ||
| 397 | #define I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT (1<<11) | ||
| 398 | #define I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT (1<<10) | ||
| 399 | #define I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT (1<<9) | ||
| 400 | #define I915_DISPLAY_PLANE_C_FLIP_PENDING_INTERRUPT (1<<8) | ||
| 401 | #define I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT (1<<7) | ||
| 402 | #define I915_DISPLAY_PIPE_A_EVENT_INTERRUPT (1<<6) | ||
| 403 | #define I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT (1<<5) | ||
| 404 | #define I915_DISPLAY_PIPE_B_EVENT_INTERRUPT (1<<4) | ||
| 405 | #define I915_DEBUG_INTERRUPT (1<<2) | ||
| 406 | #define I915_USER_INTERRUPT (1<<1) | ||
| 407 | |||
| 408 | 388 | ||
| 409 | #define I915REG_HWSTAM 0x02098 | 389 | #define I915REG_HWSTAM 0x02098 |
| 410 | #define I915REG_INT_IDENTITY_R 0x020a4 | 390 | #define I915REG_INT_IDENTITY_R 0x020a4 |
| 411 | #define I915REG_INT_MASK_R 0x020a8 | 391 | #define I915REG_INT_MASK_R 0x020a8 |
| 412 | #define I915REG_INT_ENABLE_R 0x020a0 | 392 | #define I915REG_INT_ENABLE_R 0x020a0 |
| 413 | #define I915REG_INSTPM 0x020c0 | ||
| 414 | |||
| 415 | #define PIPEADSL 0x70000 | ||
| 416 | #define PIPEBDSL 0x71000 | ||
| 417 | 393 | ||
| 418 | #define I915REG_PIPEASTAT 0x70024 | 394 | #define I915REG_PIPEASTAT 0x70024 |
| 419 | #define I915REG_PIPEBSTAT 0x71024 | 395 | #define I915REG_PIPEBSTAT 0x71024 |
| 420 | /* | ||
| 421 | * The two pipe frame counter registers are not synchronized, so | ||
| 422 | * reading a stable value is somewhat tricky. The following code | ||
| 423 | * should work: | ||
| 424 | * | ||
| 425 | * do { | ||
| 426 | * high1 = ((INREG(PIPEAFRAMEHIGH) & PIPE_FRAME_HIGH_MASK) >> | ||
| 427 | * PIPE_FRAME_HIGH_SHIFT; | ||
| 428 | * low1 = ((INREG(PIPEAFRAMEPIXEL) & PIPE_FRAME_LOW_MASK) >> | ||
| 429 | * PIPE_FRAME_LOW_SHIFT); | ||
| 430 | * high2 = ((INREG(PIPEAFRAMEHIGH) & PIPE_FRAME_HIGH_MASK) >> | ||
| 431 | * PIPE_FRAME_HIGH_SHIFT); | ||
| 432 | * } while (high1 != high2); | ||
| 433 | * frame = (high1 << 8) | low1; | ||
| 434 | */ | ||
| 435 | #define PIPEAFRAMEHIGH 0x70040 | ||
| 436 | #define PIPEBFRAMEHIGH 0x71040 | ||
| 437 | #define PIPE_FRAME_HIGH_MASK 0x0000ffff | ||
| 438 | #define PIPE_FRAME_HIGH_SHIFT 0 | ||
| 439 | #define PIPEAFRAMEPIXEL 0x70044 | ||
| 440 | #define PIPEBFRAMEPIXEL 0x71044 | ||
| 441 | 396 | ||
| 442 | #define PIPE_FRAME_LOW_MASK 0xff000000 | 397 | #define I915_VBLANK_INTERRUPT_ENABLE (1UL<<17) |
| 443 | #define PIPE_FRAME_LOW_SHIFT 24 | 398 | #define I915_VBLANK_CLEAR (1UL<<1) |
| 444 | /* | ||
| 445 | * Pixel within the current frame is counted in the PIPEAFRAMEPIXEL register | ||
| 446 | * and is 24 bits wide. | ||
| 447 | */ | ||
| 448 | #define PIPE_PIXEL_MASK 0x00ffffff | ||
| 449 | #define PIPE_PIXEL_SHIFT 0 | ||
| 450 | |||
| 451 | #define I915_FIFO_UNDERRUN_STATUS (1UL<<31) | ||
| 452 | #define I915_CRC_ERROR_ENABLE (1UL<<29) | ||
| 453 | #define I915_CRC_DONE_ENABLE (1UL<<28) | ||
| 454 | #define I915_GMBUS_EVENT_ENABLE (1UL<<27) | ||
| 455 | #define I915_VSYNC_INTERRUPT_ENABLE (1UL<<25) | ||
| 456 | #define I915_DISPLAY_LINE_COMPARE_ENABLE (1UL<<24) | ||
| 457 | #define I915_DPST_EVENT_ENABLE (1UL<<23) | ||
| 458 | #define I915_LEGACY_BLC_EVENT_ENABLE (1UL<<22) | ||
| 459 | #define I915_ODD_FIELD_INTERRUPT_ENABLE (1UL<<21) | ||
| 460 | #define I915_EVEN_FIELD_INTERRUPT_ENABLE (1UL<<20) | ||
| 461 | #define I915_START_VBLANK_INTERRUPT_ENABLE (1UL<<18) /* 965 or later */ | ||
| 462 | #define I915_VBLANK_INTERRUPT_ENABLE (1UL<<17) | ||
| 463 | #define I915_OVERLAY_UPDATED_ENABLE (1UL<<16) | ||
| 464 | #define I915_CRC_ERROR_INTERRUPT_STATUS (1UL<<13) | ||
| 465 | #define I915_CRC_DONE_INTERRUPT_STATUS (1UL<<12) | ||
| 466 | #define I915_GMBUS_INTERRUPT_STATUS (1UL<<11) | ||
| 467 | #define I915_VSYNC_INTERRUPT_STATUS (1UL<<9) | ||
| 468 | #define I915_DISPLAY_LINE_COMPARE_STATUS (1UL<<8) | ||
| 469 | #define I915_DPST_EVENT_STATUS (1UL<<7) | ||
| 470 | #define I915_LEGACY_BLC_EVENT_STATUS (1UL<<6) | ||
| 471 | #define I915_ODD_FIELD_INTERRUPT_STATUS (1UL<<5) | ||
| 472 | #define I915_EVEN_FIELD_INTERRUPT_STATUS (1UL<<4) | ||
| 473 | #define I915_START_VBLANK_INTERRUPT_STATUS (1UL<<2) /* 965 or later */ | ||
| 474 | #define I915_VBLANK_INTERRUPT_STATUS (1UL<<1) | ||
| 475 | #define I915_OVERLAY_UPDATED_STATUS (1UL<<0) | ||
| 476 | 399 | ||
| 477 | #define SRX_INDEX 0x3c4 | 400 | #define SRX_INDEX 0x3c4 |
| 478 | #define SRX_DATA 0x3c5 | 401 | #define SRX_DATA 0x3c5 |
| @@ -749,6 +672,8 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); | |||
| 749 | /** P1 value is 2 greater than this field */ | 672 | /** P1 value is 2 greater than this field */ |
| 750 | # define VGA0_PD_P1_MASK (0x1f << 0) | 673 | # define VGA0_PD_P1_MASK (0x1f << 0) |
| 751 | 674 | ||
| 675 | /* PCI D state control register */ | ||
| 676 | #define D_STATE 0x6104 | ||
| 752 | #define DSPCLK_GATE_D 0x6200 | 677 | #define DSPCLK_GATE_D 0x6200 |
| 753 | 678 | ||
| 754 | /* I830 CRTC registers */ | 679 | /* I830 CRTC registers */ |
| @@ -1059,6 +984,12 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); | |||
| 1059 | #define PIPECONF_INTERLACE_W_FIELD_INDICATION (6 << 21) | 984 | #define PIPECONF_INTERLACE_W_FIELD_INDICATION (6 << 21) |
| 1060 | #define PIPECONF_INTERLACE_FIELD_0_ONLY (7 << 21) | 985 | #define PIPECONF_INTERLACE_FIELD_0_ONLY (7 << 21) |
| 1061 | 986 | ||
| 987 | #define DSPARB 0x70030 | ||
| 988 | #define DSPARB_CSTART_MASK (0x7f << 7) | ||
| 989 | #define DSPARB_CSTART_SHIFT 7 | ||
| 990 | #define DSPARB_BSTART_MASK (0x7f) | ||
| 991 | #define DSPARB_BSTART_SHIFT 0 | ||
| 992 | |||
| 1062 | #define PIPEBCONF 0x71008 | 993 | #define PIPEBCONF 0x71008 |
| 1063 | #define PIPEBCONF_ENABLE (1<<31) | 994 | #define PIPEBCONF_ENABLE (1<<31) |
| 1064 | #define PIPEBCONF_DISABLE 0 | 995 | #define PIPEBCONF_DISABLE 0 |
diff --git a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c index 023ce66ef3a..f7f16e7a8bf 100644 --- a/drivers/char/drm/i915_irq.c +++ b/drivers/char/drm/i915_irq.c | |||
| @@ -38,109 +38,6 @@ | |||
| 38 | #define MAX_NOPID ((u32)~0) | 38 | #define MAX_NOPID ((u32)~0) |
| 39 | 39 | ||
| 40 | /** | 40 | /** |
| 41 | * i915_get_pipe - return the the pipe associated with a given plane | ||
| 42 | * @dev: DRM device | ||
| 43 | * @plane: plane to look for | ||
| 44 | * | ||
| 45 | * The Intel Mesa & 2D drivers call the vblank routines with a plane number | ||
| 46 | * rather than a pipe number, since they may not always be equal. This routine | ||
| 47 | * maps the given @plane back to a pipe number. | ||
| 48 | */ | ||
| 49 | static int | ||
| 50 | i915_get_pipe(struct drm_device *dev, int plane) | ||
| 51 | { | ||
| 52 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | ||
| 53 | u32 dspcntr; | ||
| 54 | |||
| 55 | dspcntr = plane ? I915_READ(DSPBCNTR) : I915_READ(DSPACNTR); | ||
| 56 | |||
| 57 | return dspcntr & DISPPLANE_SEL_PIPE_MASK ? 1 : 0; | ||
| 58 | } | ||
| 59 | |||
| 60 | /** | ||
| 61 | * i915_get_plane - return the the plane associated with a given pipe | ||
| 62 | * @dev: DRM device | ||
| 63 | * @pipe: pipe to look for | ||
| 64 | * | ||
| 65 | * The Intel Mesa & 2D drivers call the vblank routines with a plane number | ||
| 66 | * rather than a plane number, since they may not always be equal. This routine | ||
| 67 | * maps the given @pipe back to a plane number. | ||
| 68 | */ | ||
| 69 | static int | ||
| 70 | i915_get_plane(struct drm_device *dev, int pipe) | ||
| 71 | { | ||
| 72 | if (i915_get_pipe(dev, 0) == pipe) | ||
| 73 | return 0; | ||
| 74 | return 1; | ||
| 75 | } | ||
| 76 | |||
| 77 | /** | ||
| 78 | * i915_pipe_enabled - check if a pipe is enabled | ||
| 79 | * @dev: DRM device | ||
| 80 | * @pipe: pipe to check | ||
| 81 | * | ||
| 82 | * Reading certain registers when the pipe is disabled can hang the chip. | ||
| 83 | * Use this routine to make sure the PLL is running and the pipe is active | ||
| 84 | * before reading such registers if unsure. | ||
| 85 | */ | ||
| 86 | static int | ||
| 87 | i915_pipe_enabled(struct drm_device *dev, int pipe) | ||
| 88 | { | ||
| 89 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | ||
| 90 | unsigned long pipeconf = pipe ? PIPEBCONF : PIPEACONF; | ||
| 91 | |||
| 92 | if (I915_READ(pipeconf) & PIPEACONF_ENABLE) | ||
| 93 | return 1; | ||
| 94 | |||
| 95 | return 0; | ||
| 96 | } | ||
| 97 | |||
| 98 | /** | ||
| 99 | * Emit a synchronous flip. | ||
| 100 | * | ||
| 101 | * This function must be called with the drawable spinlock held. | ||
| 102 | */ | ||
| 103 | static void | ||
| 104 | i915_dispatch_vsync_flip(struct drm_device *dev, struct drm_drawable_info *drw, | ||
| 105 | int plane) | ||
| 106 | { | ||
| 107 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | ||
| 108 | drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; | ||
| 109 | u16 x1, y1, x2, y2; | ||
| 110 | int pf_planes = 1 << plane; | ||
| 111 | |||
| 112 | /* If the window is visible on the other plane, we have to flip on that | ||
| 113 | * plane as well. | ||
| 114 | */ | ||
| 115 | if (plane == 1) { | ||
| 116 | x1 = sarea_priv->planeA_x; | ||
| 117 | y1 = sarea_priv->planeA_y; | ||
| 118 | x2 = x1 + sarea_priv->planeA_w; | ||
| 119 | y2 = y1 + sarea_priv->planeA_h; | ||
| 120 | } else { | ||
| 121 | x1 = sarea_priv->planeB_x; | ||
| 122 | y1 = sarea_priv->planeB_y; | ||
| 123 | x2 = x1 + sarea_priv->planeB_w; | ||
| 124 | y2 = y1 + sarea_priv->planeB_h; | ||
| 125 | } | ||
| 126 | |||
| 127 | if (x2 > 0 && y2 > 0) { | ||
| 128 | int i, num_rects = drw->num_rects; | ||
| 129 | struct drm_clip_rect *rect = drw->rects; | ||
| 130 | |||
| 131 | for (i = 0; i < num_rects; i++) | ||
| 132 | if (!(rect[i].x1 >= x2 || rect[i].y1 >= y2 || | ||
| 133 | rect[i].x2 <= x1 || rect[i].y2 <= y1)) { | ||
| 134 | pf_planes = 0x3; | ||
| 135 | |||
| 136 | break; | ||
| 137 | } | ||
| 138 | } | ||
| 139 | |||
| 140 | i915_dispatch_flip(dev, pf_planes, 1); | ||
| 141 | } | ||
| 142 | |||
| 143 | /** | ||
| 144 | * Emit blits for scheduled buffer swaps. | 41 | * Emit blits for scheduled buffer swaps. |
| 145 | * | 42 | * |
| 146 | * This function will be called with the HW lock held. | 43 | * This function will be called with the HW lock held. |
| @@ -148,19 +45,20 @@ i915_dispatch_vsync_flip(struct drm_device *dev, struct drm_drawable_info *drw, | |||
| 148 | static void i915_vblank_tasklet(struct drm_device *dev) | 45 | static void i915_vblank_tasklet(struct drm_device *dev) |
| 149 | { | 46 | { |
| 150 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 47 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
| 48 | unsigned long irqflags; | ||
| 151 | struct list_head *list, *tmp, hits, *hit; | 49 | struct list_head *list, *tmp, hits, *hit; |
| 152 | int nhits, nrects, slice[2], upper[2], lower[2], i, num_pages; | 50 | int nhits, nrects, slice[2], upper[2], lower[2], i; |
| 153 | unsigned counter[2]; | 51 | unsigned counter[2] = { atomic_read(&dev->vbl_received), |
| 52 | atomic_read(&dev->vbl_received2) }; | ||
| 154 | struct drm_drawable_info *drw; | 53 | struct drm_drawable_info *drw; |
| 155 | drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; | 54 | drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; |
| 156 | u32 cpp = dev_priv->cpp, offsets[3]; | 55 | u32 cpp = dev_priv->cpp; |
| 157 | u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD | | 56 | u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD | |
| 158 | XY_SRC_COPY_BLT_WRITE_ALPHA | | 57 | XY_SRC_COPY_BLT_WRITE_ALPHA | |
| 159 | XY_SRC_COPY_BLT_WRITE_RGB) | 58 | XY_SRC_COPY_BLT_WRITE_RGB) |
| 160 | : XY_SRC_COPY_BLT_CMD; | 59 | : XY_SRC_COPY_BLT_CMD; |
| 161 | u32 src_pitch = sarea_priv->pitch * cpp; | 60 | u32 src_pitch = sarea_priv->pitch * cpp; |
| 162 | u32 dst_pitch = sarea_priv->pitch * cpp; | 61 | u32 dst_pitch = sarea_priv->pitch * cpp; |
| 163 | /* COPY rop (0xcc), map cpp to magic color depth constants */ | ||
| 164 | u32 ropcpp = (0xcc << 16) | ((cpp - 1) << 24); | 62 | u32 ropcpp = (0xcc << 16) | ((cpp - 1) << 24); |
| 165 | RING_LOCALS; | 63 | RING_LOCALS; |
| 166 | 64 | ||
| @@ -173,34 +71,24 @@ static void i915_vblank_tasklet(struct drm_device *dev) | |||
| 173 | src_pitch >>= 2; | 71 | src_pitch >>= 2; |
| 174 | } | 72 | } |
| 175 | 73 | ||
| 176 | counter[0] = drm_vblank_count(dev, 0); | ||
| 177 | counter[1] = drm_vblank_count(dev, 1); | ||
| 178 | |||
| 179 | DRM_DEBUG("\n"); | 74 | DRM_DEBUG("\n"); |
| 180 | 75 | ||
| 181 | INIT_LIST_HEAD(&hits); | 76 | INIT_LIST_HEAD(&hits); |
| 182 | 77 | ||
| 183 | nhits = nrects = 0; | 78 | nhits = nrects = 0; |
| 184 | 79 | ||
| 185 | /* No irqsave/restore necessary. This tasklet may be run in an | 80 | spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); |
| 186 | * interrupt context or normal context, but we don't have to worry | ||
| 187 | * about getting interrupted by something acquiring the lock, because | ||
| 188 | * we are the interrupt context thing that acquires the lock. | ||
| 189 | */ | ||
| 190 | spin_lock(&dev_priv->swaps_lock); | ||
| 191 | 81 | ||
| 192 | /* Find buffer swaps scheduled for this vertical blank */ | 82 | /* Find buffer swaps scheduled for this vertical blank */ |
| 193 | list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) { | 83 | list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) { |
| 194 | drm_i915_vbl_swap_t *vbl_swap = | 84 | drm_i915_vbl_swap_t *vbl_swap = |
| 195 | list_entry(list, drm_i915_vbl_swap_t, head); | 85 | list_entry(list, drm_i915_vbl_swap_t, head); |
| 196 | int pipe = i915_get_pipe(dev, vbl_swap->plane); | ||
| 197 | 86 | ||
| 198 | if ((counter[pipe] - vbl_swap->sequence) > (1<<23)) | 87 | if ((counter[vbl_swap->pipe] - vbl_swap->sequence) > (1<<23)) |
| 199 | continue; | 88 | continue; |
| 200 | 89 | ||
| 201 | list_del(list); | 90 | list_del(list); |
| 202 | dev_priv->swaps_pending--; | 91 | dev_priv->swaps_pending--; |
| 203 | drm_vblank_put(dev, pipe); | ||
| 204 | 92 | ||
| 205 | spin_unlock(&dev_priv->swaps_lock); | 93 | spin_unlock(&dev_priv->swaps_lock); |
| 206 | spin_lock(&dev->drw_lock); | 94 | spin_lock(&dev->drw_lock); |
| @@ -238,23 +126,43 @@ static void i915_vblank_tasklet(struct drm_device *dev) | |||
| 238 | spin_lock(&dev_priv->swaps_lock); | 126 | spin_lock(&dev_priv->swaps_lock); |
| 239 | } | 127 | } |
| 240 | 128 | ||
| 241 | spin_unlock(&dev_priv->swaps_lock); | 129 | if (nhits == 0) { |
| 242 | 130 | spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); | |
| 243 | if (nhits == 0) | ||
| 244 | return; | 131 | return; |
| 132 | } | ||
| 133 | |||
| 134 | spin_unlock(&dev_priv->swaps_lock); | ||
| 245 | 135 | ||
| 246 | i915_kernel_lost_context(dev); | 136 | i915_kernel_lost_context(dev); |
| 247 | 137 | ||
| 248 | upper[0] = upper[1] = 0; | 138 | if (IS_I965G(dev)) { |
| 249 | slice[0] = max(sarea_priv->planeA_h / nhits, 1); | 139 | BEGIN_LP_RING(4); |
| 250 | slice[1] = max(sarea_priv->planeB_h / nhits, 1); | 140 | |
| 251 | lower[0] = sarea_priv->planeA_y + slice[0]; | 141 | OUT_RING(GFX_OP_DRAWRECT_INFO_I965); |
| 252 | lower[1] = sarea_priv->planeB_y + slice[0]; | 142 | OUT_RING(0); |
| 143 | OUT_RING(((sarea_priv->width - 1) & 0xffff) | ((sarea_priv->height - 1) << 16)); | ||
| 144 | OUT_RING(0); | ||
| 145 | ADVANCE_LP_RING(); | ||
| 146 | } else { | ||
| 147 | BEGIN_LP_RING(6); | ||
| 253 | 148 | ||
| 254 | offsets[0] = sarea_priv->front_offset; | 149 | OUT_RING(GFX_OP_DRAWRECT_INFO); |
| 255 | offsets[1] = sarea_priv->back_offset; | 150 | OUT_RING(0); |
| 256 | offsets[2] = sarea_priv->third_offset; | 151 | OUT_RING(0); |
| 257 | num_pages = sarea_priv->third_handle ? 3 : 2; | 152 | OUT_RING(sarea_priv->width | sarea_priv->height << 16); |
| 153 | OUT_RING(sarea_priv->width | sarea_priv->height << 16); | ||
| 154 | OUT_RING(0); | ||
| 155 | |||
| 156 | ADVANCE_LP_RING(); | ||
| 157 | } | ||
| 158 | |||
| 159 | sarea_priv->ctxOwner = DRM_KERNEL_CONTEXT; | ||
| 160 | |||
| 161 | upper[0] = upper[1] = 0; | ||
| 162 | slice[0] = max(sarea_priv->pipeA_h / nhits, 1); | ||
| 163 | slice[1] = max(sarea_priv->pipeB_h / nhits, 1); | ||
| 164 | lower[0] = sarea_priv->pipeA_y + slice[0]; | ||
| 165 | lower[1] = sarea_priv->pipeB_y + slice[0]; | ||
| 258 | 166 | ||
| 259 | spin_lock(&dev->drw_lock); | 167 | spin_lock(&dev->drw_lock); |
| 260 | 168 | ||
| @@ -266,8 +174,6 @@ static void i915_vblank_tasklet(struct drm_device *dev) | |||
| 266 | for (i = 0; i++ < nhits; | 174 | for (i = 0; i++ < nhits; |
| 267 | upper[0] = lower[0], lower[0] += slice[0], | 175 | upper[0] = lower[0], lower[0] += slice[0], |
| 268 | upper[1] = lower[1], lower[1] += slice[1]) { | 176 | upper[1] = lower[1], lower[1] += slice[1]) { |
| 269 | int init_drawrect = 1; | ||
| 270 | |||
| 271 | if (i == nhits) | 177 | if (i == nhits) |
| 272 | lower[0] = lower[1] = sarea_priv->height; | 178 | lower[0] = lower[1] = sarea_priv->height; |
| 273 | 179 | ||
| @@ -275,7 +181,7 @@ static void i915_vblank_tasklet(struct drm_device *dev) | |||
| 275 | drm_i915_vbl_swap_t *swap_hit = | 181 | drm_i915_vbl_swap_t *swap_hit = |
| 276 | list_entry(hit, drm_i915_vbl_swap_t, head); | 182 | list_entry(hit, drm_i915_vbl_swap_t, head); |
| 277 | struct drm_clip_rect *rect; | 183 | struct drm_clip_rect *rect; |
| 278 | int num_rects, plane, front, back; | 184 | int num_rects, pipe; |
| 279 | unsigned short top, bottom; | 185 | unsigned short top, bottom; |
| 280 | 186 | ||
| 281 | drw = drm_get_drawable_info(dev, swap_hit->drw_id); | 187 | drw = drm_get_drawable_info(dev, swap_hit->drw_id); |
| @@ -283,50 +189,10 @@ static void i915_vblank_tasklet(struct drm_device *dev) | |||
| 283 | if (!drw) | 189 | if (!drw) |
| 284 | continue; | 190 | continue; |
| 285 | 191 | ||
| 286 | plane = swap_hit->plane; | ||
| 287 | |||
| 288 | if (swap_hit->flip) { | ||
| 289 | i915_dispatch_vsync_flip(dev, drw, plane); | ||
| 290 | continue; | ||
| 291 | } | ||
| 292 | |||
| 293 | if (init_drawrect) { | ||
| 294 | int width = sarea_priv->width; | ||
| 295 | int height = sarea_priv->height; | ||
| 296 | if (IS_I965G(dev)) { | ||
| 297 | BEGIN_LP_RING(4); | ||
| 298 | |||
| 299 | OUT_RING(GFX_OP_DRAWRECT_INFO_I965); | ||
| 300 | OUT_RING(0); | ||
| 301 | OUT_RING(((width - 1) & 0xffff) | ((height - 1) << 16)); | ||
| 302 | OUT_RING(0); | ||
| 303 | |||
| 304 | ADVANCE_LP_RING(); | ||
| 305 | } else { | ||
| 306 | BEGIN_LP_RING(6); | ||
| 307 | |||
| 308 | OUT_RING(GFX_OP_DRAWRECT_INFO); | ||
| 309 | OUT_RING(0); | ||
| 310 | OUT_RING(0); | ||
| 311 | OUT_RING(((width - 1) & 0xffff) | ((height - 1) << 16)); | ||
| 312 | OUT_RING(0); | ||
| 313 | OUT_RING(0); | ||
| 314 | |||
| 315 | ADVANCE_LP_RING(); | ||
| 316 | } | ||
| 317 | |||
| 318 | sarea_priv->ctxOwner = DRM_KERNEL_CONTEXT; | ||
| 319 | |||
| 320 | init_drawrect = 0; | ||
| 321 | } | ||
| 322 | |||
| 323 | rect = drw->rects; | 192 | rect = drw->rects; |
| 324 | top = upper[plane]; | 193 | pipe = swap_hit->pipe; |
| 325 | bottom = lower[plane]; | 194 | top = upper[pipe]; |
| 326 | 195 | bottom = lower[pipe]; | |
| 327 | front = (dev_priv->sarea_priv->pf_current_page >> | ||
| 328 | (2 * plane)) & 0x3; | ||
| 329 | back = (front + 1) % num_pages; | ||
| 330 | 196 | ||
| 331 | for (num_rects = drw->num_rects; num_rects--; rect++) { | 197 | for (num_rects = drw->num_rects; num_rects--; rect++) { |
| 332 | int y1 = max(rect->y1, top); | 198 | int y1 = max(rect->y1, top); |
| @@ -341,17 +207,17 @@ static void i915_vblank_tasklet(struct drm_device *dev) | |||
| 341 | OUT_RING(ropcpp | dst_pitch); | 207 | OUT_RING(ropcpp | dst_pitch); |
| 342 | OUT_RING((y1 << 16) | rect->x1); | 208 | OUT_RING((y1 << 16) | rect->x1); |
| 343 | OUT_RING((y2 << 16) | rect->x2); | 209 | OUT_RING((y2 << 16) | rect->x2); |
| 344 | OUT_RING(offsets[front]); | 210 | OUT_RING(sarea_priv->front_offset); |
| 345 | OUT_RING((y1 << 16) | rect->x1); | 211 | OUT_RING((y1 << 16) | rect->x1); |
| 346 | OUT_RING(src_pitch); | 212 | OUT_RING(src_pitch); |
| 347 | OUT_RING(offsets[back]); | 213 | OUT_RING(sarea_priv->back_offset); |
| 348 | 214 | ||
| 349 | ADVANCE_LP_RING(); | 215 | ADVANCE_LP_RING(); |
| 350 | } | 216 | } |
| 351 | } | 217 | } |
| 352 | } | 218 | } |
| 353 | 219 | ||
| 354 | spin_unlock(&dev->drw_lock); | 220 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); |
| 355 | 221 | ||
| 356 | list_for_each_safe(hit, tmp, &hits) { | 222 | list_for_each_safe(hit, tmp, &hits) { |
| 357 | drm_i915_vbl_swap_t *swap_hit = | 223 | drm_i915_vbl_swap_t *swap_hit = |
| @@ -363,112 +229,67 @@ static void i915_vblank_tasklet(struct drm_device *dev) | |||
| 363 | } | 229 | } |
| 364 | } | 230 | } |
| 365 | 231 | ||
| 366 | u32 i915_get_vblank_counter(struct drm_device *dev, int plane) | ||
| 367 | { | ||
| 368 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | ||
| 369 | unsigned long high_frame; | ||
| 370 | unsigned long low_frame; | ||
| 371 | u32 high1, high2, low, count; | ||
| 372 | int pipe; | ||
| 373 | |||
| 374 | pipe = i915_get_pipe(dev, plane); | ||
| 375 | high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH; | ||
| 376 | low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL; | ||
| 377 | |||
| 378 | if (!i915_pipe_enabled(dev, pipe)) { | ||
| 379 | printk(KERN_ERR "trying to get vblank count for disabled " | ||
| 380 | "pipe %d\n", pipe); | ||
| 381 | return 0; | ||
| 382 | } | ||
| 383 | |||
| 384 | /* | ||
| 385 | * High & low register fields aren't synchronized, so make sure | ||
| 386 | * we get a low value that's stable across two reads of the high | ||
| 387 | * register. | ||
| 388 | */ | ||
| 389 | do { | ||
| 390 | high1 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >> | ||
| 391 | PIPE_FRAME_HIGH_SHIFT); | ||
| 392 | low = ((I915_READ(low_frame) & PIPE_FRAME_LOW_MASK) >> | ||
| 393 | PIPE_FRAME_LOW_SHIFT); | ||
| 394 | high2 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >> | ||
| 395 | PIPE_FRAME_HIGH_SHIFT); | ||
| 396 | } while (high1 != high2); | ||
| 397 | |||
| 398 | count = (high1 << 8) | low; | ||
| 399 | |||
| 400 | /* count may be reset by other driver(e.g. 2D driver), | ||
| 401 | we have no way to know if it is wrapped or resetted | ||
| 402 | when count is zero. do a rough guess. | ||
| 403 | */ | ||
| 404 | if (count == 0 && dev->last_vblank[pipe] < dev->max_vblank_count/2) | ||
| 405 | dev->last_vblank[pipe] = 0; | ||
| 406 | |||
| 407 | return count; | ||
| 408 | } | ||
| 409 | |||
| 410 | irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) | 232 | irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) |
| 411 | { | 233 | { |
| 412 | struct drm_device *dev = (struct drm_device *) arg; | 234 | struct drm_device *dev = (struct drm_device *) arg; |
| 413 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 235 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
| 414 | u32 iir; | 236 | u16 temp; |
| 415 | u32 pipea_stats, pipeb_stats; | 237 | u32 pipea_stats, pipeb_stats; |
| 416 | int vblank = 0; | ||
| 417 | |||
| 418 | iir = I915_READ(I915REG_INT_IDENTITY_R); | ||
| 419 | if (iir == 0) { | ||
| 420 | DRM_DEBUG ("iir 0x%08x im 0x%08x ie 0x%08x pipea 0x%08x pipeb 0x%08x\n", | ||
| 421 | iir, | ||
| 422 | I915_READ(I915REG_INT_MASK_R), | ||
| 423 | I915_READ(I915REG_INT_ENABLE_R), | ||
| 424 | I915_READ(I915REG_PIPEASTAT), | ||
| 425 | I915_READ(I915REG_PIPEBSTAT)); | ||
| 426 | return IRQ_NONE; | ||
| 427 | } | ||
| 428 | 238 | ||
| 429 | /* | 239 | pipea_stats = I915_READ(I915REG_PIPEASTAT); |
| 430 | * Clear the PIPE(A|B)STAT regs before the IIR otherwise | 240 | pipeb_stats = I915_READ(I915REG_PIPEBSTAT); |
| 431 | * we may get extra interrupts. | ||
| 432 | */ | ||
| 433 | if (iir & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) { | ||
| 434 | pipea_stats = I915_READ(I915REG_PIPEASTAT); | ||
| 435 | if (pipea_stats & (I915_START_VBLANK_INTERRUPT_STATUS| | ||
| 436 | I915_VBLANK_INTERRUPT_STATUS)) | ||
| 437 | { | ||
| 438 | vblank++; | ||
| 439 | drm_handle_vblank(dev, i915_get_plane(dev, 0)); | ||
| 440 | } | ||
| 441 | I915_WRITE(I915REG_PIPEASTAT, pipea_stats); | ||
| 442 | } | ||
| 443 | if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) { | ||
| 444 | pipeb_stats = I915_READ(I915REG_PIPEBSTAT); | ||
| 445 | if (pipeb_stats & (I915_START_VBLANK_INTERRUPT_STATUS| | ||
| 446 | I915_VBLANK_INTERRUPT_STATUS)) | ||
| 447 | { | ||
| 448 | vblank++; | ||
| 449 | drm_handle_vblank(dev, i915_get_plane(dev, 1)); | ||
| 450 | } | ||
| 451 | I915_WRITE(I915REG_PIPEBSTAT, pipeb_stats); | ||
| 452 | } | ||
| 453 | 241 | ||
| 454 | if (dev_priv->sarea_priv) | 242 | temp = I915_READ16(I915REG_INT_IDENTITY_R); |
| 455 | dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); | ||
| 456 | 243 | ||
| 457 | I915_WRITE(I915REG_INT_IDENTITY_R, iir); | 244 | temp &= (USER_INT_FLAG | VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG); |
| 458 | (void) I915_READ(I915REG_INT_IDENTITY_R); /* Flush posted write */ | ||
| 459 | 245 | ||
| 460 | if (iir & I915_USER_INTERRUPT) { | 246 | DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp); |
| 247 | |||
| 248 | if (temp == 0) | ||
| 249 | return IRQ_NONE; | ||
| 250 | |||
| 251 | I915_WRITE16(I915REG_INT_IDENTITY_R, temp); | ||
| 252 | (void) I915_READ16(I915REG_INT_IDENTITY_R); | ||
| 253 | DRM_READMEMORYBARRIER(); | ||
| 254 | |||
| 255 | dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); | ||
| 256 | |||
| 257 | if (temp & USER_INT_FLAG) | ||
| 461 | DRM_WAKEUP(&dev_priv->irq_queue); | 258 | DRM_WAKEUP(&dev_priv->irq_queue); |
| 462 | } | 259 | |
| 463 | if (vblank) { | 260 | if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) { |
| 261 | int vblank_pipe = dev_priv->vblank_pipe; | ||
| 262 | |||
| 263 | if ((vblank_pipe & | ||
| 264 | (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) | ||
| 265 | == (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) { | ||
| 266 | if (temp & VSYNC_PIPEA_FLAG) | ||
| 267 | atomic_inc(&dev->vbl_received); | ||
| 268 | if (temp & VSYNC_PIPEB_FLAG) | ||
| 269 | atomic_inc(&dev->vbl_received2); | ||
| 270 | } else if (((temp & VSYNC_PIPEA_FLAG) && | ||
| 271 | (vblank_pipe & DRM_I915_VBLANK_PIPE_A)) || | ||
| 272 | ((temp & VSYNC_PIPEB_FLAG) && | ||
| 273 | (vblank_pipe & DRM_I915_VBLANK_PIPE_B))) | ||
| 274 | atomic_inc(&dev->vbl_received); | ||
| 275 | |||
| 276 | DRM_WAKEUP(&dev->vbl_queue); | ||
| 277 | drm_vbl_send_signals(dev); | ||
| 278 | |||
| 464 | if (dev_priv->swaps_pending > 0) | 279 | if (dev_priv->swaps_pending > 0) |
| 465 | drm_locked_tasklet(dev, i915_vblank_tasklet); | 280 | drm_locked_tasklet(dev, i915_vblank_tasklet); |
| 281 | I915_WRITE(I915REG_PIPEASTAT, | ||
| 282 | pipea_stats|I915_VBLANK_INTERRUPT_ENABLE| | ||
| 283 | I915_VBLANK_CLEAR); | ||
| 284 | I915_WRITE(I915REG_PIPEBSTAT, | ||
| 285 | pipeb_stats|I915_VBLANK_INTERRUPT_ENABLE| | ||
| 286 | I915_VBLANK_CLEAR); | ||
| 466 | } | 287 | } |
| 467 | 288 | ||
| 468 | return IRQ_HANDLED; | 289 | return IRQ_HANDLED; |
| 469 | } | 290 | } |
| 470 | 291 | ||
| 471 | static int i915_emit_irq(struct drm_device *dev) | 292 | static int i915_emit_irq(struct drm_device * dev) |
| 472 | { | 293 | { |
| 473 | drm_i915_private_t *dev_priv = dev->dev_private; | 294 | drm_i915_private_t *dev_priv = dev->dev_private; |
| 474 | RING_LOCALS; | 295 | RING_LOCALS; |
| @@ -515,12 +336,42 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr) | |||
| 515 | READ_BREADCRUMB(dev_priv), (int)dev_priv->counter); | 336 | READ_BREADCRUMB(dev_priv), (int)dev_priv->counter); |
| 516 | } | 337 | } |
| 517 | 338 | ||
| 518 | if (dev_priv->sarea_priv) | 339 | dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); |
| 519 | dev_priv->sarea_priv->last_dispatch = | ||
| 520 | READ_BREADCRUMB(dev_priv); | ||
| 521 | return ret; | 340 | return ret; |
| 522 | } | 341 | } |
| 523 | 342 | ||
| 343 | static int i915_driver_vblank_do_wait(struct drm_device *dev, unsigned int *sequence, | ||
| 344 | atomic_t *counter) | ||
| 345 | { | ||
| 346 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
| 347 | unsigned int cur_vblank; | ||
| 348 | int ret = 0; | ||
| 349 | |||
| 350 | if (!dev_priv) { | ||
| 351 | DRM_ERROR("called with no initialization\n"); | ||
| 352 | return -EINVAL; | ||
| 353 | } | ||
| 354 | |||
| 355 | DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, | ||
| 356 | (((cur_vblank = atomic_read(counter)) | ||
| 357 | - *sequence) <= (1<<23))); | ||
| 358 | |||
| 359 | *sequence = cur_vblank; | ||
| 360 | |||
| 361 | return ret; | ||
| 362 | } | ||
| 363 | |||
| 364 | |||
| 365 | int i915_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence) | ||
| 366 | { | ||
| 367 | return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received); | ||
| 368 | } | ||
| 369 | |||
| 370 | int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence) | ||
| 371 | { | ||
| 372 | return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received2); | ||
| 373 | } | ||
| 374 | |||
| 524 | /* Needs the lock as it touches the ring. | 375 | /* Needs the lock as it touches the ring. |
| 525 | */ | 376 | */ |
| 526 | int i915_irq_emit(struct drm_device *dev, void *data, | 377 | int i915_irq_emit(struct drm_device *dev, void *data, |
| @@ -563,96 +414,18 @@ int i915_irq_wait(struct drm_device *dev, void *data, | |||
| 563 | return i915_wait_irq(dev, irqwait->irq_seq); | 414 | return i915_wait_irq(dev, irqwait->irq_seq); |
| 564 | } | 415 | } |
| 565 | 416 | ||
| 566 | int i915_enable_vblank(struct drm_device *dev, int plane) | ||
| 567 | { | ||
| 568 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | ||
| 569 | int pipe = i915_get_pipe(dev, plane); | ||
| 570 | u32 pipestat_reg = 0; | ||
| 571 | u32 pipestat; | ||
| 572 | |||
| 573 | switch (pipe) { | ||
| 574 | case 0: | ||
| 575 | pipestat_reg = I915REG_PIPEASTAT; | ||
| 576 | dev_priv->irq_enable_reg |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT; | ||
| 577 | break; | ||
| 578 | case 1: | ||
| 579 | pipestat_reg = I915REG_PIPEBSTAT; | ||
| 580 | dev_priv->irq_enable_reg |= I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; | ||
| 581 | break; | ||
| 582 | default: | ||
| 583 | DRM_ERROR("tried to enable vblank on non-existent pipe %d\n", | ||
| 584 | pipe); | ||
| 585 | break; | ||
| 586 | } | ||
| 587 | |||
| 588 | if (pipestat_reg) | ||
| 589 | { | ||
| 590 | pipestat = I915_READ (pipestat_reg); | ||
| 591 | /* | ||
| 592 | * Older chips didn't have the start vblank interrupt, | ||
| 593 | * but | ||
| 594 | */ | ||
| 595 | if (IS_I965G (dev)) | ||
| 596 | pipestat |= I915_START_VBLANK_INTERRUPT_ENABLE; | ||
| 597 | else | ||
| 598 | pipestat |= I915_VBLANK_INTERRUPT_ENABLE; | ||
| 599 | /* | ||
| 600 | * Clear any pending status | ||
| 601 | */ | ||
| 602 | pipestat |= (I915_START_VBLANK_INTERRUPT_STATUS | | ||
| 603 | I915_VBLANK_INTERRUPT_STATUS); | ||
| 604 | I915_WRITE(pipestat_reg, pipestat); | ||
| 605 | } | ||
| 606 | I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); | ||
| 607 | |||
| 608 | return 0; | ||
| 609 | } | ||
| 610 | |||
| 611 | void i915_disable_vblank(struct drm_device *dev, int plane) | ||
| 612 | { | ||
| 613 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | ||
| 614 | int pipe = i915_get_pipe(dev, plane); | ||
| 615 | u32 pipestat_reg = 0; | ||
| 616 | u32 pipestat; | ||
| 617 | |||
| 618 | switch (pipe) { | ||
| 619 | case 0: | ||
| 620 | pipestat_reg = I915REG_PIPEASTAT; | ||
| 621 | dev_priv->irq_enable_reg &= ~I915_DISPLAY_PIPE_A_EVENT_INTERRUPT; | ||
| 622 | break; | ||
| 623 | case 1: | ||
| 624 | pipestat_reg = I915REG_PIPEBSTAT; | ||
| 625 | dev_priv->irq_enable_reg &= ~I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; | ||
| 626 | break; | ||
| 627 | default: | ||
| 628 | DRM_ERROR("tried to disable vblank on non-existent pipe %d\n", | ||
| 629 | pipe); | ||
| 630 | break; | ||
| 631 | } | ||
| 632 | |||
| 633 | I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); | ||
| 634 | if (pipestat_reg) | ||
| 635 | { | ||
| 636 | pipestat = I915_READ (pipestat_reg); | ||
| 637 | pipestat &= ~(I915_START_VBLANK_INTERRUPT_ENABLE | | ||
| 638 | I915_VBLANK_INTERRUPT_ENABLE); | ||
| 639 | /* | ||
| 640 | * Clear any pending status | ||
| 641 | */ | ||
| 642 | pipestat |= (I915_START_VBLANK_INTERRUPT_STATUS | | ||
| 643 | I915_VBLANK_INTERRUPT_STATUS); | ||
| 644 | I915_WRITE(pipestat_reg, pipestat); | ||
| 645 | } | ||
| 646 | } | ||
| 647 | |||
| 648 | static void i915_enable_interrupt (struct drm_device *dev) | 417 | static void i915_enable_interrupt (struct drm_device *dev) |
| 649 | { | 418 | { |
| 650 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 419 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
| 420 | u16 flag; | ||
| 651 | 421 | ||
| 652 | dev_priv->irq_enable_reg |= I915_USER_INTERRUPT; | 422 | flag = 0; |
| 423 | if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A) | ||
| 424 | flag |= VSYNC_PIPEA_FLAG; | ||
| 425 | if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B) | ||
| 426 | flag |= VSYNC_PIPEB_FLAG; | ||
| 653 | 427 | ||
| 654 | I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); | 428 | I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG | flag); |
| 655 | dev_priv->irq_enabled = 1; | ||
| 656 | } | 429 | } |
| 657 | 430 | ||
| 658 | /* Set the vblank monitor pipe | 431 | /* Set the vblank monitor pipe |
| @@ -675,6 +448,8 @@ int i915_vblank_pipe_set(struct drm_device *dev, void *data, | |||
| 675 | 448 | ||
| 676 | dev_priv->vblank_pipe = pipe->pipe; | 449 | dev_priv->vblank_pipe = pipe->pipe; |
| 677 | 450 | ||
| 451 | i915_enable_interrupt (dev); | ||
| 452 | |||
| 678 | return 0; | 453 | return 0; |
| 679 | } | 454 | } |
| 680 | 455 | ||
| @@ -692,9 +467,9 @@ int i915_vblank_pipe_get(struct drm_device *dev, void *data, | |||
| 692 | 467 | ||
| 693 | flag = I915_READ(I915REG_INT_ENABLE_R); | 468 | flag = I915_READ(I915REG_INT_ENABLE_R); |
| 694 | pipe->pipe = 0; | 469 | pipe->pipe = 0; |
| 695 | if (flag & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) | 470 | if (flag & VSYNC_PIPEA_FLAG) |
| 696 | pipe->pipe |= DRM_I915_VBLANK_PIPE_A; | 471 | pipe->pipe |= DRM_I915_VBLANK_PIPE_A; |
| 697 | if (flag & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) | 472 | if (flag & VSYNC_PIPEB_FLAG) |
| 698 | pipe->pipe |= DRM_I915_VBLANK_PIPE_B; | 473 | pipe->pipe |= DRM_I915_VBLANK_PIPE_B; |
| 699 | 474 | ||
| 700 | return 0; | 475 | return 0; |
| @@ -709,30 +484,27 @@ int i915_vblank_swap(struct drm_device *dev, void *data, | |||
| 709 | drm_i915_private_t *dev_priv = dev->dev_private; | 484 | drm_i915_private_t *dev_priv = dev->dev_private; |
| 710 | drm_i915_vblank_swap_t *swap = data; | 485 | drm_i915_vblank_swap_t *swap = data; |
| 711 | drm_i915_vbl_swap_t *vbl_swap; | 486 | drm_i915_vbl_swap_t *vbl_swap; |
| 712 | unsigned int pipe, seqtype, curseq, plane; | 487 | unsigned int pipe, seqtype, curseq; |
| 713 | unsigned long irqflags; | 488 | unsigned long irqflags; |
| 714 | struct list_head *list; | 489 | struct list_head *list; |
| 715 | int ret; | ||
| 716 | 490 | ||
| 717 | if (!dev_priv) { | 491 | if (!dev_priv) { |
| 718 | DRM_ERROR("%s called with no initialization\n", __func__); | 492 | DRM_ERROR("%s called with no initialization\n", __func__); |
| 719 | return -EINVAL; | 493 | return -EINVAL; |
| 720 | } | 494 | } |
| 721 | 495 | ||
| 722 | if (!dev_priv->sarea_priv || dev_priv->sarea_priv->rotation) { | 496 | if (dev_priv->sarea_priv->rotation) { |
| 723 | DRM_DEBUG("Rotation not supported\n"); | 497 | DRM_DEBUG("Rotation not supported\n"); |
| 724 | return -EINVAL; | 498 | return -EINVAL; |
| 725 | } | 499 | } |
| 726 | 500 | ||
| 727 | if (swap->seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE | | 501 | if (swap->seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE | |
| 728 | _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS | | 502 | _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS)) { |
| 729 | _DRM_VBLANK_FLIP)) { | ||
| 730 | DRM_ERROR("Invalid sequence type 0x%x\n", swap->seqtype); | 503 | DRM_ERROR("Invalid sequence type 0x%x\n", swap->seqtype); |
| 731 | return -EINVAL; | 504 | return -EINVAL; |
| 732 | } | 505 | } |
| 733 | 506 | ||
| 734 | plane = (swap->seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0; | 507 | pipe = (swap->seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0; |
| 735 | pipe = i915_get_pipe(dev, plane); | ||
| 736 | 508 | ||
| 737 | seqtype = swap->seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE); | 509 | seqtype = swap->seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE); |
| 738 | 510 | ||
| @@ -743,11 +515,6 @@ int i915_vblank_swap(struct drm_device *dev, void *data, | |||
| 743 | 515 | ||
| 744 | spin_lock_irqsave(&dev->drw_lock, irqflags); | 516 | spin_lock_irqsave(&dev->drw_lock, irqflags); |
| 745 | 517 | ||
| 746 | /* It makes no sense to schedule a swap for a drawable that doesn't have | ||
| 747 | * valid information at this point. E.g. this could mean that the X | ||
| 748 | * server is too old to push drawable information to the DRM, in which | ||
| 749 | * case all such swaps would become ineffective. | ||
| 750 | */ | ||
| 751 | if (!drm_get_drawable_info(dev, swap->drawable)) { | 518 | if (!drm_get_drawable_info(dev, swap->drawable)) { |
| 752 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | 519 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); |
| 753 | DRM_DEBUG("Invalid drawable ID %d\n", swap->drawable); | 520 | DRM_DEBUG("Invalid drawable ID %d\n", swap->drawable); |
| @@ -756,8 +523,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data, | |||
| 756 | 523 | ||
| 757 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | 524 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); |
| 758 | 525 | ||
| 759 | drm_update_vblank_count(dev, pipe); | 526 | curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received); |
| 760 | curseq = drm_vblank_count(dev, pipe); | ||
| 761 | 527 | ||
| 762 | if (seqtype == _DRM_VBLANK_RELATIVE) | 528 | if (seqtype == _DRM_VBLANK_RELATIVE) |
| 763 | swap->sequence += curseq; | 529 | swap->sequence += curseq; |
| @@ -771,43 +537,14 @@ int i915_vblank_swap(struct drm_device *dev, void *data, | |||
| 771 | } | 537 | } |
| 772 | } | 538 | } |
| 773 | 539 | ||
| 774 | if (swap->seqtype & _DRM_VBLANK_FLIP) { | ||
| 775 | swap->sequence--; | ||
| 776 | |||
| 777 | if ((curseq - swap->sequence) <= (1<<23)) { | ||
| 778 | struct drm_drawable_info *drw; | ||
| 779 | |||
| 780 | LOCK_TEST_WITH_RETURN(dev, file_priv); | ||
| 781 | |||
| 782 | spin_lock_irqsave(&dev->drw_lock, irqflags); | ||
| 783 | |||
| 784 | drw = drm_get_drawable_info(dev, swap->drawable); | ||
| 785 | |||
| 786 | if (!drw) { | ||
| 787 | spin_unlock_irqrestore(&dev->drw_lock, | ||
| 788 | irqflags); | ||
| 789 | DRM_DEBUG("Invalid drawable ID %d\n", | ||
| 790 | swap->drawable); | ||
| 791 | return -EINVAL; | ||
| 792 | } | ||
| 793 | |||
| 794 | i915_dispatch_vsync_flip(dev, drw, plane); | ||
| 795 | |||
| 796 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | ||
| 797 | |||
| 798 | return 0; | ||
| 799 | } | ||
| 800 | } | ||
| 801 | |||
| 802 | spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); | 540 | spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); |
| 803 | 541 | ||
| 804 | list_for_each(list, &dev_priv->vbl_swaps.head) { | 542 | list_for_each(list, &dev_priv->vbl_swaps.head) { |
| 805 | vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head); | 543 | vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head); |
| 806 | 544 | ||
| 807 | if (vbl_swap->drw_id == swap->drawable && | 545 | if (vbl_swap->drw_id == swap->drawable && |
| 808 | vbl_swap->plane == plane && | 546 | vbl_swap->pipe == pipe && |
| 809 | vbl_swap->sequence == swap->sequence) { | 547 | vbl_swap->sequence == swap->sequence) { |
| 810 | vbl_swap->flip = (swap->seqtype & _DRM_VBLANK_FLIP); | ||
| 811 | spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); | 548 | spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); |
| 812 | DRM_DEBUG("Already scheduled\n"); | 549 | DRM_DEBUG("Already scheduled\n"); |
| 813 | return 0; | 550 | return 0; |
| @@ -830,19 +567,9 @@ int i915_vblank_swap(struct drm_device *dev, void *data, | |||
| 830 | 567 | ||
| 831 | DRM_DEBUG("\n"); | 568 | DRM_DEBUG("\n"); |
| 832 | 569 | ||
| 833 | ret = drm_vblank_get(dev, pipe); | ||
| 834 | if (ret) { | ||
| 835 | drm_free(vbl_swap, sizeof(*vbl_swap), DRM_MEM_DRIVER); | ||
| 836 | return ret; | ||
| 837 | } | ||
| 838 | |||
| 839 | vbl_swap->drw_id = swap->drawable; | 570 | vbl_swap->drw_id = swap->drawable; |
| 840 | vbl_swap->plane = plane; | 571 | vbl_swap->pipe = pipe; |
| 841 | vbl_swap->sequence = swap->sequence; | 572 | vbl_swap->sequence = swap->sequence; |
| 842 | vbl_swap->flip = (swap->seqtype & _DRM_VBLANK_FLIP); | ||
| 843 | |||
| 844 | if (vbl_swap->flip) | ||
| 845 | swap->sequence++; | ||
| 846 | 573 | ||
| 847 | spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); | 574 | spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); |
| 848 | 575 | ||
| @@ -860,57 +587,37 @@ void i915_driver_irq_preinstall(struct drm_device * dev) | |||
| 860 | { | 587 | { |
| 861 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 588 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
| 862 | 589 | ||
| 863 | I915_WRITE16(I915REG_HWSTAM, 0xeffe); | 590 | I915_WRITE16(I915REG_HWSTAM, 0xfffe); |
| 864 | I915_WRITE16(I915REG_INT_MASK_R, 0x0); | 591 | I915_WRITE16(I915REG_INT_MASK_R, 0x0); |
| 865 | I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); | 592 | I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); |
| 866 | } | 593 | } |
| 867 | 594 | ||
| 868 | int i915_driver_irq_postinstall(struct drm_device * dev) | 595 | void i915_driver_irq_postinstall(struct drm_device * dev) |
| 869 | { | 596 | { |
| 870 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 597 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
| 871 | int ret, num_pipes = 2; | ||
| 872 | 598 | ||
| 873 | spin_lock_init(&dev_priv->swaps_lock); | 599 | spin_lock_init(&dev_priv->swaps_lock); |
| 874 | INIT_LIST_HEAD(&dev_priv->vbl_swaps.head); | 600 | INIT_LIST_HEAD(&dev_priv->vbl_swaps.head); |
| 875 | dev_priv->swaps_pending = 0; | 601 | dev_priv->swaps_pending = 0; |
| 876 | 602 | ||
| 877 | dev_priv->user_irq_refcount = 0; | 603 | if (!dev_priv->vblank_pipe) |
| 878 | dev_priv->irq_enable_reg = 0; | 604 | dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A; |
| 879 | |||
| 880 | ret = drm_vblank_init(dev, num_pipes); | ||
| 881 | if (ret) | ||
| 882 | return ret; | ||
| 883 | |||
| 884 | dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ | ||
| 885 | |||
| 886 | i915_enable_interrupt(dev); | 605 | i915_enable_interrupt(dev); |
| 887 | DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); | 606 | DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); |
| 888 | |||
| 889 | /* | ||
| 890 | * Initialize the hardware status page IRQ location. | ||
| 891 | */ | ||
| 892 | |||
| 893 | I915_WRITE(I915REG_INSTPM, (1 << 5) | (1 << 21)); | ||
| 894 | return 0; | ||
| 895 | } | 607 | } |
| 896 | 608 | ||
| 897 | void i915_driver_irq_uninstall(struct drm_device * dev) | 609 | void i915_driver_irq_uninstall(struct drm_device * dev) |
| 898 | { | 610 | { |
| 899 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 611 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
| 900 | u32 temp; | 612 | u16 temp; |
| 901 | 613 | ||
| 902 | if (!dev_priv) | 614 | if (!dev_priv) |
| 903 | return; | 615 | return; |
| 904 | 616 | ||
| 905 | dev_priv->irq_enabled = 0; | 617 | I915_WRITE16(I915REG_HWSTAM, 0xffff); |
| 906 | I915_WRITE(I915REG_HWSTAM, 0xffffffff); | 618 | I915_WRITE16(I915REG_INT_MASK_R, 0xffff); |
| 907 | I915_WRITE(I915REG_INT_MASK_R, 0xffffffff); | 619 | I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); |
| 908 | I915_WRITE(I915REG_INT_ENABLE_R, 0x0); | 620 | |
| 909 | 621 | temp = I915_READ16(I915REG_INT_IDENTITY_R); | |
| 910 | temp = I915_READ(I915REG_PIPEASTAT); | 622 | I915_WRITE16(I915REG_INT_IDENTITY_R, temp); |
| 911 | I915_WRITE(I915REG_PIPEASTAT, temp); | ||
| 912 | temp = I915_READ(I915REG_PIPEBSTAT); | ||
| 913 | I915_WRITE(I915REG_PIPEBSTAT, temp); | ||
| 914 | temp = I915_READ(I915REG_INT_IDENTITY_R); | ||
| 915 | I915_WRITE(I915REG_INT_IDENTITY_R, temp); | ||
| 916 | } | 623 | } |
diff --git a/drivers/char/drm/mga_drv.c b/drivers/char/drm/mga_drv.c index 6b3790939e7..5572939fc7d 100644 --- a/drivers/char/drm/mga_drv.c +++ b/drivers/char/drm/mga_drv.c | |||
| @@ -45,16 +45,15 @@ 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, | ||
| 49 | .dev_priv_size = sizeof(drm_mga_buf_priv_t), | 50 | .dev_priv_size = sizeof(drm_mga_buf_priv_t), |
| 50 | .load = mga_driver_load, | 51 | .load = mga_driver_load, |
| 51 | .unload = mga_driver_unload, | 52 | .unload = mga_driver_unload, |
| 52 | .lastclose = mga_driver_lastclose, | 53 | .lastclose = mga_driver_lastclose, |
| 53 | .dma_quiescent = mga_driver_dma_quiescent, | 54 | .dma_quiescent = mga_driver_dma_quiescent, |
| 54 | .device_is_agp = mga_driver_device_is_agp, | 55 | .device_is_agp = mga_driver_device_is_agp, |
| 55 | .get_vblank_counter = mga_get_vblank_counter, | 56 | .vblank_wait = mga_driver_vblank_wait, |
| 56 | .enable_vblank = mga_enable_vblank, | ||
| 57 | .disable_vblank = mga_disable_vblank, | ||
| 58 | .irq_preinstall = mga_driver_irq_preinstall, | 57 | .irq_preinstall = mga_driver_irq_preinstall, |
| 59 | .irq_postinstall = mga_driver_irq_postinstall, | 58 | .irq_postinstall = mga_driver_irq_postinstall, |
| 60 | .irq_uninstall = mga_driver_irq_uninstall, | 59 | .irq_uninstall = mga_driver_irq_uninstall, |
diff --git a/drivers/char/drm/mga_drv.h b/drivers/char/drm/mga_drv.h index 8f7291f3636..f6ebd24bd58 100644 --- a/drivers/char/drm/mga_drv.h +++ b/drivers/char/drm/mga_drv.h | |||
| @@ -120,7 +120,6 @@ 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. */ | ||
| 124 | wait_queue_head_t fence_queue; | 123 | wait_queue_head_t fence_queue; |
| 125 | atomic_t last_fence_retired; | 124 | atomic_t last_fence_retired; |
| 126 | u32 next_fence_to_post; | 125 | u32 next_fence_to_post; |
| @@ -182,14 +181,11 @@ extern int mga_warp_install_microcode(drm_mga_private_t * dev_priv); | |||
| 182 | extern int mga_warp_init(drm_mga_private_t * dev_priv); | 181 | extern int mga_warp_init(drm_mga_private_t * dev_priv); |
| 183 | 182 | ||
| 184 | /* mga_irq.c */ | 183 | /* 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); | ||
| 188 | extern int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence); | 184 | extern int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence); |
| 189 | extern int mga_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence); | 185 | extern int mga_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence); |
| 190 | extern irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS); | 186 | extern irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS); |
| 191 | extern void mga_driver_irq_preinstall(struct drm_device * dev); | 187 | extern void mga_driver_irq_preinstall(struct drm_device * dev); |
| 192 | extern int mga_driver_irq_postinstall(struct drm_device * dev); | 188 | extern void mga_driver_irq_postinstall(struct drm_device * dev); |
| 193 | extern void mga_driver_irq_uninstall(struct drm_device * dev); | 189 | extern void mga_driver_irq_uninstall(struct drm_device * dev); |
| 194 | extern long mga_compat_ioctl(struct file *filp, unsigned int cmd, | 190 | extern long mga_compat_ioctl(struct file *filp, unsigned int cmd, |
| 195 | unsigned long arg); | 191 | unsigned long arg); |
diff --git a/drivers/char/drm/mga_irq.c b/drivers/char/drm/mga_irq.c index 06852fb4b27..9302cb8f0f8 100644 --- a/drivers/char/drm/mga_irq.c +++ b/drivers/char/drm/mga_irq.c | |||
| @@ -35,20 +35,6 @@ | |||
| 35 | #include "mga_drm.h" | 35 | #include "mga_drm.h" |
| 36 | #include "mga_drv.h" | 36 | #include "mga_drv.h" |
| 37 | 37 | ||
| 38 | u32 mga_get_vblank_counter(struct drm_device *dev, int crtc) | ||
| 39 | { | ||
| 40 | const drm_mga_private_t *const dev_priv = | ||
| 41 | (drm_mga_private_t *) dev->dev_private; | ||
| 42 | |||
| 43 | if (crtc != 0) { | ||
| 44 | return 0; | ||
| 45 | } | ||
| 46 | |||
| 47 | |||
| 48 | return atomic_read(&dev_priv->vbl_received); | ||
| 49 | } | ||
| 50 | |||
| 51 | |||
| 52 | irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS) | 38 | irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS) |
| 53 | { | 39 | { |
| 54 | struct drm_device *dev = (struct drm_device *) arg; | 40 | struct drm_device *dev = (struct drm_device *) arg; |
| @@ -61,8 +47,9 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS) | |||
| 61 | /* VBLANK interrupt */ | 47 | /* VBLANK interrupt */ |
| 62 | if (status & MGA_VLINEPEN) { | 48 | if (status & MGA_VLINEPEN) { |
| 63 | MGA_WRITE(MGA_ICLEAR, MGA_VLINEICLR); | 49 | MGA_WRITE(MGA_ICLEAR, MGA_VLINEICLR); |
| 64 | atomic_inc(&dev_priv->vbl_received); | 50 | atomic_inc(&dev->vbl_received); |
| 65 | drm_handle_vblank(dev, 0); | 51 | DRM_WAKEUP(&dev->vbl_queue); |
| 52 | drm_vbl_send_signals(dev); | ||
| 66 | handled = 1; | 53 | handled = 1; |
| 67 | } | 54 | } |
| 68 | 55 | ||
| @@ -91,34 +78,22 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS) | |||
| 91 | return IRQ_NONE; | 78 | return IRQ_NONE; |
| 92 | } | 79 | } |
| 93 | 80 | ||
| 94 | int mga_enable_vblank(struct drm_device *dev, int crtc) | 81 | int mga_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence) |
| 95 | { | 82 | { |
| 96 | drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; | 83 | unsigned int cur_vblank; |
| 97 | 84 | int ret = 0; | |
| 98 | if (crtc != 0) { | ||
| 99 | DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", | ||
| 100 | crtc); | ||
| 101 | return 0; | ||
| 102 | } | ||
| 103 | |||
| 104 | MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); | ||
| 105 | return 0; | ||
| 106 | } | ||
| 107 | 85 | ||
| 86 | /* Assume that the user has missed the current sequence number | ||
| 87 | * by about a day rather than she wants to wait for years | ||
| 88 | * using vertical blanks... | ||
| 89 | */ | ||
| 90 | DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, | ||
| 91 | (((cur_vblank = atomic_read(&dev->vbl_received)) | ||
| 92 | - *sequence) <= (1 << 23))); | ||
| 108 | 93 | ||
| 109 | void mga_disable_vblank(struct drm_device *dev, int crtc) | 94 | *sequence = cur_vblank; |
| 110 | { | ||
| 111 | if (crtc != 0) { | ||
| 112 | DRM_ERROR("tried to disable vblank on non-existent crtc %d\n", | ||
| 113 | crtc); | ||
| 114 | } | ||
| 115 | 95 | ||
| 116 | /* Do *NOT* disable the vertical refresh interrupt. MGA doesn't have | 96 | return ret; |
| 117 | * a nice hardware counter that tracks the number of refreshes when | ||
| 118 | * the interrupt is disabled, and the kernel doesn't know the refresh | ||
| 119 | * rate to calculate an estimate. | ||
| 120 | */ | ||
| 121 | /* MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); */ | ||
| 122 | } | 97 | } |
| 123 | 98 | ||
| 124 | int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence) | 99 | int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence) |
| @@ -150,22 +125,14 @@ void mga_driver_irq_preinstall(struct drm_device * dev) | |||
| 150 | MGA_WRITE(MGA_ICLEAR, ~0); | 125 | MGA_WRITE(MGA_ICLEAR, ~0); |
| 151 | } | 126 | } |
| 152 | 127 | ||
| 153 | int mga_driver_irq_postinstall(struct drm_device * dev) | 128 | void mga_driver_irq_postinstall(struct drm_device * dev) |
| 154 | { | 129 | { |
| 155 | drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; | 130 | drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; |
| 156 | int ret; | ||
| 157 | |||
| 158 | ret = drm_vblank_init(dev, 1); | ||
| 159 | if (ret) | ||
| 160 | return ret; | ||
| 161 | 131 | ||
| 162 | DRM_INIT_WAITQUEUE(&dev_priv->fence_queue); | 132 | DRM_INIT_WAITQUEUE(&dev_priv->fence_queue); |
| 163 | 133 | ||
| 164 | /* Turn on soft trap interrupt. Vertical blank interrupts are enabled | 134 | /* Turn on vertical blank interrupt and soft trap interrupt. */ |
| 165 | * in mga_enable_vblank. | 135 | MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); |
| 166 | */ | ||
| 167 | MGA_WRITE(MGA_IEN, MGA_SOFTRAPEN); | ||
| 168 | return 0; | ||
| 169 | } | 136 | } |
| 170 | 137 | ||
| 171 | void mga_driver_irq_uninstall(struct drm_device * dev) | 138 | void mga_driver_irq_uninstall(struct drm_device * dev) |
diff --git a/drivers/char/drm/r128_drv.c b/drivers/char/drm/r128_drv.c index 2888aa01ebc..6108e7587e1 100644 --- a/drivers/char/drm/r128_drv.c +++ b/drivers/char/drm/r128_drv.c | |||
| @@ -43,13 +43,12 @@ 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, | ||
| 47 | .dev_priv_size = sizeof(drm_r128_buf_priv_t), | 48 | .dev_priv_size = sizeof(drm_r128_buf_priv_t), |
| 48 | .preclose = r128_driver_preclose, | 49 | .preclose = r128_driver_preclose, |
| 49 | .lastclose = r128_driver_lastclose, | 50 | .lastclose = r128_driver_lastclose, |
| 50 | .get_vblank_counter = r128_get_vblank_counter, | 51 | .vblank_wait = r128_driver_vblank_wait, |
| 51 | .enable_vblank = r128_enable_vblank, | ||
| 52 | .disable_vblank = r128_disable_vblank, | ||
| 53 | .irq_preinstall = r128_driver_irq_preinstall, | 52 | .irq_preinstall = r128_driver_irq_preinstall, |
| 54 | .irq_postinstall = r128_driver_irq_postinstall, | 53 | .irq_postinstall = r128_driver_irq_postinstall, |
| 55 | .irq_uninstall = r128_driver_irq_uninstall, | 54 | .irq_uninstall = r128_driver_irq_uninstall, |
diff --git a/drivers/char/drm/r128_drv.h b/drivers/char/drm/r128_drv.h index 80af9e09e75..011105e51ac 100644 --- a/drivers/char/drm/r128_drv.h +++ b/drivers/char/drm/r128_drv.h | |||
| @@ -97,8 +97,6 @@ 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 | |||
| 102 | u32 color_fmt; | 100 | u32 color_fmt; |
| 103 | unsigned int front_offset; | 101 | unsigned int front_offset; |
| 104 | unsigned int front_pitch; | 102 | unsigned int front_pitch; |
| @@ -151,12 +149,11 @@ extern int r128_wait_ring(drm_r128_private_t * dev_priv, int n); | |||
| 151 | extern int r128_do_cce_idle(drm_r128_private_t * dev_priv); | 149 | extern int r128_do_cce_idle(drm_r128_private_t * dev_priv); |
| 152 | extern int r128_do_cleanup_cce(struct drm_device * dev); | 150 | extern int r128_do_cleanup_cce(struct drm_device * dev); |
| 153 | 151 | ||
| 154 | extern int r128_enable_vblank(struct drm_device *dev, int crtc); | 152 | extern int r128_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence); |
| 155 | extern void r128_disable_vblank(struct drm_device *dev, int crtc); | 153 | |
| 156 | extern u32 r128_get_vblank_counter(struct drm_device *dev, int crtc); | ||
| 157 | extern irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS); | 154 | extern irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS); |
| 158 | extern void r128_driver_irq_preinstall(struct drm_device * dev); | 155 | extern void r128_driver_irq_preinstall(struct drm_device * dev); |
| 159 | extern int r128_driver_irq_postinstall(struct drm_device * dev); | 156 | extern void r128_driver_irq_postinstall(struct drm_device * dev); |
| 160 | extern void r128_driver_irq_uninstall(struct drm_device * dev); | 157 | extern void r128_driver_irq_uninstall(struct drm_device * dev); |
| 161 | extern void r128_driver_lastclose(struct drm_device * dev); | 158 | extern void r128_driver_lastclose(struct drm_device * dev); |
| 162 | extern void r128_driver_preclose(struct drm_device * dev, | 159 | extern void r128_driver_preclose(struct drm_device * dev, |
diff --git a/drivers/char/drm/r128_irq.c b/drivers/char/drm/r128_irq.c index 5b95bd898f9..c76fdca7662 100644 --- a/drivers/char/drm/r128_irq.c +++ b/drivers/char/drm/r128_irq.c | |||
| @@ -35,16 +35,6 @@ | |||
| 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 | |||
| 48 | irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS) | 38 | irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS) |
| 49 | { | 39 | { |
| 50 | struct drm_device *dev = (struct drm_device *) arg; | 40 | struct drm_device *dev = (struct drm_device *) arg; |
| @@ -56,38 +46,30 @@ irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS) | |||
| 56 | /* VBLANK interrupt */ | 46 | /* VBLANK interrupt */ |
| 57 | if (status & R128_CRTC_VBLANK_INT) { | 47 | if (status & R128_CRTC_VBLANK_INT) { |
| 58 | R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK); | 48 | R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK); |
| 59 | atomic_inc(&dev_priv->vbl_received); | 49 | atomic_inc(&dev->vbl_received); |
| 60 | drm_handle_vblank(dev, 0); | 50 | DRM_WAKEUP(&dev->vbl_queue); |
| 51 | drm_vbl_send_signals(dev); | ||
| 61 | return IRQ_HANDLED; | 52 | return IRQ_HANDLED; |
| 62 | } | 53 | } |
| 63 | return IRQ_NONE; | 54 | return IRQ_NONE; |
| 64 | } | 55 | } |
| 65 | 56 | ||
| 66 | int r128_enable_vblank(struct drm_device *dev, int crtc) | 57 | int r128_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence) |
| 67 | { | 58 | { |
| 68 | drm_r128_private_t *dev_priv = dev->dev_private; | 59 | unsigned int cur_vblank; |
| 69 | 60 | int ret = 0; | |
| 70 | if (crtc != 0) { | ||
| 71 | DRM_ERROR("%s: bad crtc %d\n", __FUNCTION__, crtc); | ||
| 72 | return -EINVAL; | ||
| 73 | } | ||
| 74 | 61 | ||
| 75 | R128_WRITE(R128_GEN_INT_CNTL, R128_CRTC_VBLANK_INT_EN); | 62 | /* Assume that the user has missed the current sequence number |
| 76 | return 0; | 63 | * by about a day rather than she wants to wait for years |
| 77 | } | 64 | * using vertical blanks... |
| 65 | */ | ||
| 66 | DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, | ||
| 67 | (((cur_vblank = atomic_read(&dev->vbl_received)) | ||
| 68 | - *sequence) <= (1 << 23))); | ||
| 78 | 69 | ||
| 79 | void r128_disable_vblank(struct drm_device *dev, int crtc) | 70 | *sequence = cur_vblank; |
| 80 | { | ||
| 81 | if (crtc != 0) | ||
| 82 | DRM_ERROR("%s: bad crtc %d\n", __FUNCTION__, crtc); | ||
| 83 | 71 | ||
| 84 | /* | 72 | return ret; |
| 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 | */ | ||
| 91 | } | 73 | } |
| 92 | 74 | ||
| 93 | void r128_driver_irq_preinstall(struct drm_device * dev) | 75 | void r128_driver_irq_preinstall(struct drm_device * dev) |
| @@ -100,9 +82,12 @@ void r128_driver_irq_preinstall(struct drm_device * dev) | |||
| 100 | R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK); | 82 | R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK); |
| 101 | } | 83 | } |
| 102 | 84 | ||
| 103 | int r128_driver_irq_postinstall(struct drm_device * dev) | 85 | void r128_driver_irq_postinstall(struct drm_device * dev) |
| 104 | { | 86 | { |
| 105 | return drm_vblank_init(dev, 1); | 87 | drm_r128_private_t *dev_priv = (drm_r128_private_t *) dev->dev_private; |
| 88 | |||
| 89 | /* Turn on VBL interrupt */ | ||
| 90 | R128_WRITE(R128_GEN_INT_CNTL, R128_CRTC_VBLANK_INT_EN); | ||
| 106 | } | 91 | } |
| 107 | 92 | ||
| 108 | void r128_driver_irq_uninstall(struct drm_device * dev) | 93 | void r128_driver_irq_uninstall(struct drm_device * dev) |
diff --git a/drivers/char/drm/radeon_drv.c b/drivers/char/drm/radeon_drv.c index a2610319624..349ac3d3b84 100644 --- a/drivers/char/drm/radeon_drv.c +++ b/drivers/char/drm/radeon_drv.c | |||
| @@ -59,7 +59,8 @@ static struct pci_device_id pciidlist[] = { | |||
| 59 | static struct drm_driver driver = { | 59 | static struct drm_driver driver = { |
| 60 | .driver_features = | 60 | .driver_features = |
| 61 | DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG | | 61 | DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG | |
| 62 | DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED, | 62 | DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED | |
| 63 | DRIVER_IRQ_VBL | DRIVER_IRQ_VBL2, | ||
| 63 | .dev_priv_size = sizeof(drm_radeon_buf_priv_t), | 64 | .dev_priv_size = sizeof(drm_radeon_buf_priv_t), |
| 64 | .load = radeon_driver_load, | 65 | .load = radeon_driver_load, |
| 65 | .firstopen = radeon_driver_firstopen, | 66 | .firstopen = radeon_driver_firstopen, |
| @@ -68,9 +69,8 @@ static struct drm_driver driver = { | |||
| 68 | .postclose = radeon_driver_postclose, | 69 | .postclose = radeon_driver_postclose, |
| 69 | .lastclose = radeon_driver_lastclose, | 70 | .lastclose = radeon_driver_lastclose, |
| 70 | .unload = radeon_driver_unload, | 71 | .unload = radeon_driver_unload, |
| 71 | .get_vblank_counter = radeon_get_vblank_counter, | 72 | .vblank_wait = radeon_driver_vblank_wait, |
| 72 | .enable_vblank = radeon_enable_vblank, | 73 | .vblank_wait2 = radeon_driver_vblank_wait2, |
| 73 | .disable_vblank = radeon_disable_vblank, | ||
| 74 | .dri_library_name = dri_library_name, | 74 | .dri_library_name = dri_library_name, |
| 75 | .irq_preinstall = radeon_driver_irq_preinstall, | 75 | .irq_preinstall = radeon_driver_irq_preinstall, |
| 76 | .irq_postinstall = radeon_driver_irq_postinstall, | 76 | .irq_postinstall = radeon_driver_irq_postinstall, |
diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h index b791420bd3d..173ae620223 100644 --- a/drivers/char/drm/radeon_drv.h +++ b/drivers/char/drm/radeon_drv.h | |||
| @@ -304,9 +304,6 @@ typedef struct drm_radeon_private { | |||
| 304 | 304 | ||
| 305 | u32 scratch_ages[5]; | 305 | u32 scratch_ages[5]; |
| 306 | 306 | ||
| 307 | unsigned int crtc_last_cnt; | ||
| 308 | unsigned int crtc2_last_cnt; | ||
| 309 | |||
| 310 | /* starting from here on, data is preserved accross an open */ | 307 | /* starting from here on, data is preserved accross an open */ |
| 311 | uint32_t flags; /* see radeon_chip_flags */ | 308 | uint32_t flags; /* see radeon_chip_flags */ |
| 312 | unsigned long fb_aper_offset; | 309 | unsigned long fb_aper_offset; |
| @@ -377,13 +374,13 @@ extern int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file * | |||
| 377 | extern int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv); | 374 | extern int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv); |
| 378 | 375 | ||
| 379 | extern void radeon_do_release(struct drm_device * dev); | 376 | extern void radeon_do_release(struct drm_device * dev); |
| 380 | extern u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc); | 377 | extern int radeon_driver_vblank_wait(struct drm_device * dev, |
| 381 | extern int radeon_enable_vblank(struct drm_device *dev, int crtc); | 378 | unsigned int *sequence); |
| 382 | extern void radeon_disable_vblank(struct drm_device *dev, int crtc); | 379 | extern int radeon_driver_vblank_wait2(struct drm_device * dev, |
| 383 | extern void radeon_do_release(struct drm_device * dev); | 380 | unsigned int *sequence); |
| 384 | extern irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS); | 381 | extern irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS); |
| 385 | extern void radeon_driver_irq_preinstall(struct drm_device * dev); | 382 | extern void radeon_driver_irq_preinstall(struct drm_device * dev); |
| 386 | extern int radeon_driver_irq_postinstall(struct drm_device * dev); | 383 | extern void radeon_driver_irq_postinstall(struct drm_device * dev); |
| 387 | extern void radeon_driver_irq_uninstall(struct drm_device * dev); | 384 | extern void radeon_driver_irq_uninstall(struct drm_device * dev); |
| 388 | extern int radeon_vblank_crtc_get(struct drm_device *dev); | 385 | extern int radeon_vblank_crtc_get(struct drm_device *dev); |
| 389 | extern int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value); | 386 | extern int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value); |
| @@ -561,12 +558,6 @@ extern int r300_do_cp_cmdbuf(struct drm_device * dev, | |||
| 561 | ? DRM_READ32( dev_priv->ring_rptr, RADEON_SCRATCHOFF(x) ) \ | 558 | ? DRM_READ32( dev_priv->ring_rptr, RADEON_SCRATCHOFF(x) ) \ |
| 562 | : RADEON_READ( RADEON_SCRATCH_REG0 + 4*(x) ) ) | 559 | : RADEON_READ( RADEON_SCRATCH_REG0 + 4*(x) ) ) |
| 563 | 560 | ||
| 564 | #define RADEON_CRTC_CRNT_FRAME 0x0214 | ||
| 565 | #define RADEON_CRTC2_CRNT_FRAME 0x0314 | ||
| 566 | |||
| 567 | #define RADEON_CRTC_STATUS 0x005c | ||
| 568 | #define RADEON_CRTC2_STATUS 0x03fc | ||
| 569 | |||
| 570 | #define RADEON_GEN_INT_CNTL 0x0040 | 561 | #define RADEON_GEN_INT_CNTL 0x0040 |
| 571 | # define RADEON_CRTC_VBLANK_MASK (1 << 0) | 562 | # define RADEON_CRTC_VBLANK_MASK (1 << 0) |
| 572 | # define RADEON_CRTC2_VBLANK_MASK (1 << 9) | 563 | # define RADEON_CRTC2_VBLANK_MASK (1 << 9) |
diff --git a/drivers/char/drm/radeon_irq.c b/drivers/char/drm/radeon_irq.c index 507d6b747a1..009af3814b6 100644 --- a/drivers/char/drm/radeon_irq.c +++ b/drivers/char/drm/radeon_irq.c | |||
| @@ -35,61 +35,12 @@ | |||
| 35 | #include "radeon_drm.h" | 35 | #include "radeon_drm.h" |
| 36 | #include "radeon_drv.h" | 36 | #include "radeon_drv.h" |
| 37 | 37 | ||
| 38 | static void radeon_irq_set_state(struct drm_device *dev, u32 mask, int state) | 38 | static __inline__ u32 radeon_acknowledge_irqs(drm_radeon_private_t * dev_priv, |
| 39 | u32 mask) | ||
| 39 | { | 40 | { |
| 40 | drm_radeon_private_t *dev_priv = dev->dev_private; | 41 | u32 irqs = RADEON_READ(RADEON_GEN_INT_STATUS) & mask; |
| 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 | int radeon_enable_vblank(struct drm_device *dev, int crtc) | ||
| 51 | { | ||
| 52 | switch (crtc) { | ||
| 53 | case 0: | ||
| 54 | radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 1); | ||
| 55 | break; | ||
| 56 | case 1: | ||
| 57 | radeon_irq_set_state(dev, RADEON_CRTC2_VBLANK_MASK, 1); | ||
| 58 | break; | ||
| 59 | default: | ||
| 60 | DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", | ||
| 61 | crtc); | ||
| 62 | return EINVAL; | ||
| 63 | } | ||
| 64 | |||
| 65 | return 0; | ||
| 66 | } | ||
| 67 | |||
| 68 | void radeon_disable_vblank(struct drm_device *dev, int crtc) | ||
| 69 | { | ||
| 70 | switch (crtc) { | ||
| 71 | case 0: | ||
| 72 | radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 0); | ||
| 73 | break; | ||
| 74 | case 1: | ||
| 75 | radeon_irq_set_state(dev, RADEON_CRTC2_VBLANK_MASK, 0); | ||
| 76 | break; | ||
| 77 | default: | ||
| 78 | DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", | ||
| 79 | crtc); | ||
| 80 | break; | ||
| 81 | } | ||
| 82 | } | ||
| 83 | |||
| 84 | static __inline__ u32 radeon_acknowledge_irqs(drm_radeon_private_t * dev_priv) | ||
| 85 | { | ||
| 86 | u32 irqs = RADEON_READ(RADEON_GEN_INT_STATUS) & | ||
| 87 | (RADEON_SW_INT_TEST | RADEON_CRTC_VBLANK_STAT | | ||
| 88 | RADEON_CRTC2_VBLANK_STAT); | ||
| 89 | |||
| 90 | if (irqs) | 42 | if (irqs) |
| 91 | RADEON_WRITE(RADEON_GEN_INT_STATUS, irqs); | 43 | RADEON_WRITE(RADEON_GEN_INT_STATUS, irqs); |
| 92 | |||
| 93 | return irqs; | 44 | return irqs; |
| 94 | } | 45 | } |
| 95 | 46 | ||
| @@ -121,21 +72,39 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS) | |||
| 121 | /* Only consider the bits we're interested in - others could be used | 72 | /* Only consider the bits we're interested in - others could be used |
| 122 | * outside the DRM | 73 | * outside the DRM |
| 123 | */ | 74 | */ |
| 124 | stat = radeon_acknowledge_irqs(dev_priv); | 75 | stat = radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK | |
| 76 | RADEON_CRTC_VBLANK_STAT | | ||
| 77 | RADEON_CRTC2_VBLANK_STAT)); | ||
| 125 | if (!stat) | 78 | if (!stat) |
| 126 | return IRQ_NONE; | 79 | return IRQ_NONE; |
| 127 | 80 | ||
| 128 | stat &= dev_priv->irq_enable_reg; | 81 | stat &= dev_priv->irq_enable_reg; |
| 129 | 82 | ||
| 130 | /* SW interrupt */ | 83 | /* SW interrupt */ |
| 131 | if (stat & RADEON_SW_INT_TEST) | 84 | if (stat & RADEON_SW_INT_TEST) { |
| 132 | DRM_WAKEUP(&dev_priv->swi_queue); | 85 | DRM_WAKEUP(&dev_priv->swi_queue); |
| 86 | } | ||
| 133 | 87 | ||
| 134 | /* VBLANK interrupt */ | 88 | /* VBLANK interrupt */ |
| 135 | if (stat & RADEON_CRTC_VBLANK_STAT) | 89 | if (stat & (RADEON_CRTC_VBLANK_STAT|RADEON_CRTC2_VBLANK_STAT)) { |
| 136 | drm_handle_vblank(dev, 0); | 90 | int vblank_crtc = dev_priv->vblank_crtc; |
| 137 | if (stat & RADEON_CRTC2_VBLANK_STAT) | 91 | |
| 138 | drm_handle_vblank(dev, 1); | 92 | if ((vblank_crtc & |
| 93 | (DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2)) == | ||
| 94 | (DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2)) { | ||
| 95 | if (stat & RADEON_CRTC_VBLANK_STAT) | ||
| 96 | atomic_inc(&dev->vbl_received); | ||
| 97 | if (stat & RADEON_CRTC2_VBLANK_STAT) | ||
| 98 | atomic_inc(&dev->vbl_received2); | ||
| 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 | } | ||
| 139 | 108 | ||
| 140 | return IRQ_HANDLED; | 109 | return IRQ_HANDLED; |
| 141 | } | 110 | } |
| @@ -175,27 +144,54 @@ static int radeon_wait_irq(struct drm_device * dev, int swi_nr) | |||
| 175 | return ret; | 144 | return ret; |
| 176 | } | 145 | } |
| 177 | 146 | ||
| 178 | u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc) | 147 | static int radeon_driver_vblank_do_wait(struct drm_device * dev, |
| 148 | unsigned int *sequence, int crtc) | ||
| 179 | { | 149 | { |
| 180 | drm_radeon_private_t *dev_priv = dev->dev_private; | 150 | drm_radeon_private_t *dev_priv = |
| 181 | u32 crtc_cnt_reg, crtc_status_reg; | 151 | (drm_radeon_private_t *) dev->dev_private; |
| 182 | 152 | unsigned int cur_vblank; | |
| 153 | int ret = 0; | ||
| 154 | int ack = 0; | ||
| 155 | atomic_t *counter; | ||
| 183 | if (!dev_priv) { | 156 | if (!dev_priv) { |
| 184 | DRM_ERROR("called with no initialization\n"); | 157 | DRM_ERROR("called with no initialization\n"); |
| 185 | return -EINVAL; | 158 | return -EINVAL; |
| 186 | } | 159 | } |
| 187 | 160 | ||
| 188 | if (crtc == 0) { | 161 | if (crtc == DRM_RADEON_VBLANK_CRTC1) { |
| 189 | crtc_cnt_reg = RADEON_CRTC_CRNT_FRAME; | 162 | counter = &dev->vbl_received; |
| 190 | crtc_status_reg = RADEON_CRTC_STATUS; | 163 | ack |= RADEON_CRTC_VBLANK_STAT; |
| 191 | } else if (crtc == 1) { | 164 | } else if (crtc == DRM_RADEON_VBLANK_CRTC2) { |
| 192 | crtc_cnt_reg = RADEON_CRTC2_CRNT_FRAME; | 165 | counter = &dev->vbl_received2; |
| 193 | crtc_status_reg = RADEON_CRTC2_STATUS; | 166 | ack |= RADEON_CRTC2_VBLANK_STAT; |
| 194 | } else { | 167 | } else |
| 195 | return -EINVAL; | 168 | return -EINVAL; |
| 196 | } | ||
| 197 | 169 | ||
| 198 | return RADEON_READ(crtc_cnt_reg) + (RADEON_READ(crtc_status_reg) & 1); | 170 | radeon_acknowledge_irqs(dev_priv, ack); |
| 171 | |||
| 172 | dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE; | ||
| 173 | |||
| 174 | /* Assume that the user has missed the current sequence number | ||
| 175 | * by about a day rather than she wants to wait for years | ||
| 176 | * using vertical blanks... | ||
| 177 | */ | ||
| 178 | DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, | ||
| 179 | (((cur_vblank = atomic_read(counter)) | ||
| 180 | - *sequence) <= (1 << 23))); | ||
| 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); | ||
| 199 | } | 195 | } |
| 200 | 196 | ||
| 201 | /* Needs the lock as it touches the ring. | 197 | /* Needs the lock as it touches the ring. |
| @@ -238,6 +234,21 @@ int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_pr | |||
| 238 | return radeon_wait_irq(dev, irqwait->irq_seq); | 234 | return radeon_wait_irq(dev, irqwait->irq_seq); |
| 239 | } | 235 | } |
| 240 | 236 | ||
| 237 | static 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 | |||
| 241 | /* drm_dma.h hooks | 252 | /* drm_dma.h hooks |
| 242 | */ | 253 | */ |
| 243 | void radeon_driver_irq_preinstall(struct drm_device * dev) | 254 | void radeon_driver_irq_preinstall(struct drm_device * dev) |
| @@ -249,27 +260,20 @@ void radeon_driver_irq_preinstall(struct drm_device * dev) | |||
| 249 | RADEON_WRITE(RADEON_GEN_INT_CNTL, 0); | 260 | RADEON_WRITE(RADEON_GEN_INT_CNTL, 0); |
| 250 | 261 | ||
| 251 | /* Clear bits if they're already high */ | 262 | /* Clear bits if they're already high */ |
| 252 | radeon_acknowledge_irqs(dev_priv); | 263 | radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK | |
| 264 | RADEON_CRTC_VBLANK_STAT | | ||
| 265 | RADEON_CRTC2_VBLANK_STAT)); | ||
| 253 | } | 266 | } |
| 254 | 267 | ||
| 255 | int radeon_driver_irq_postinstall(struct drm_device * dev) | 268 | void radeon_driver_irq_postinstall(struct drm_device * dev) |
| 256 | { | 269 | { |
| 257 | drm_radeon_private_t *dev_priv = | 270 | drm_radeon_private_t *dev_priv = |
| 258 | (drm_radeon_private_t *) dev->dev_private; | 271 | (drm_radeon_private_t *) dev->dev_private; |
| 259 | int ret; | ||
| 260 | 272 | ||
| 261 | atomic_set(&dev_priv->swi_emitted, 0); | 273 | atomic_set(&dev_priv->swi_emitted, 0); |
| 262 | DRM_INIT_WAITQUEUE(&dev_priv->swi_queue); | 274 | DRM_INIT_WAITQUEUE(&dev_priv->swi_queue); |
| 263 | 275 | ||
| 264 | ret = drm_vblank_init(dev, 2); | 276 | radeon_enable_interrupt(dev); |
| 265 | if (ret) | ||
| 266 | return ret; | ||
| 267 | |||
| 268 | dev->max_vblank_count = 0x001fffff; | ||
| 269 | |||
| 270 | radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1); | ||
| 271 | |||
| 272 | return 0; | ||
| 273 | } | 277 | } |
| 274 | 278 | ||
| 275 | void radeon_driver_irq_uninstall(struct drm_device * dev) | 279 | void radeon_driver_irq_uninstall(struct drm_device * dev) |
| @@ -311,5 +315,6 @@ int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value) | |||
| 311 | return -EINVAL; | 315 | return -EINVAL; |
| 312 | } | 316 | } |
| 313 | dev_priv->vblank_crtc = (unsigned int)value; | 317 | dev_priv->vblank_crtc = (unsigned int)value; |
| 318 | radeon_enable_interrupt(dev); | ||
| 314 | return 0; | 319 | return 0; |
| 315 | } | 320 | } |
diff --git a/drivers/char/drm/via_drv.c b/drivers/char/drm/via_drv.c index 37870a4a3dc..80c01cdfa37 100644 --- a/drivers/char/drm/via_drv.c +++ b/drivers/char/drm/via_drv.c | |||
| @@ -40,13 +40,11 @@ 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, | 43 | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL, |
| 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 | .get_vblank_counter = via_get_vblank_counter, | 47 | .vblank_wait = via_driver_vblank_wait, |
| 48 | .enable_vblank = via_enable_vblank, | ||
| 49 | .disable_vblank = via_disable_vblank, | ||
| 50 | .irq_preinstall = via_driver_irq_preinstall, | 48 | .irq_preinstall = via_driver_irq_preinstall, |
| 51 | .irq_postinstall = via_driver_irq_postinstall, | 49 | .irq_postinstall = via_driver_irq_postinstall, |
| 52 | .irq_uninstall = via_driver_irq_uninstall, | 50 | .irq_uninstall = via_driver_irq_uninstall, |
diff --git a/drivers/char/drm/via_drv.h b/drivers/char/drm/via_drv.h index fe67030e39a..2daae81874c 100644 --- a/drivers/char/drm/via_drv.h +++ b/drivers/char/drm/via_drv.h | |||
| @@ -75,7 +75,6 @@ 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; | ||
| 79 | drm_via_state_t hc_state; | 78 | drm_via_state_t hc_state; |
| 80 | char pci_buf[VIA_PCI_BUF_SIZE]; | 79 | char pci_buf[VIA_PCI_BUF_SIZE]; |
| 81 | const uint32_t *fire_offsets[VIA_FIRE_BUF_SIZE]; | 80 | const uint32_t *fire_offsets[VIA_FIRE_BUF_SIZE]; |
| @@ -131,13 +130,11 @@ extern int via_init_context(struct drm_device * dev, int context); | |||
| 131 | extern int via_final_context(struct drm_device * dev, int context); | 130 | extern int via_final_context(struct drm_device * dev, int context); |
| 132 | 131 | ||
| 133 | extern int via_do_cleanup_map(struct drm_device * dev); | 132 | extern int via_do_cleanup_map(struct drm_device * dev); |
| 134 | extern u32 via_get_vblank_counter(struct drm_device *dev, int crtc); | 133 | extern int via_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence); |
| 135 | extern int via_enable_vblank(struct drm_device *dev, int crtc); | ||
| 136 | extern void via_disable_vblank(struct drm_device *dev, int crtc); | ||
| 137 | 134 | ||
| 138 | extern irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS); | 135 | extern irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS); |
| 139 | extern void via_driver_irq_preinstall(struct drm_device * dev); | 136 | extern void via_driver_irq_preinstall(struct drm_device * dev); |
| 140 | extern int via_driver_irq_postinstall(struct drm_device * dev); | 137 | extern void via_driver_irq_postinstall(struct drm_device * dev); |
| 141 | extern void via_driver_irq_uninstall(struct drm_device * dev); | 138 | extern void via_driver_irq_uninstall(struct drm_device * dev); |
| 142 | 139 | ||
| 143 | extern int via_dma_cleanup(struct drm_device * dev); | 140 | extern int via_dma_cleanup(struct drm_device * dev); |
diff --git a/drivers/char/drm/via_irq.c b/drivers/char/drm/via_irq.c index f1ab6fc7c07..c6bb978a110 100644 --- a/drivers/char/drm/via_irq.c +++ b/drivers/char/drm/via_irq.c | |||
| @@ -92,17 +92,8 @@ static int via_irqmap_unichrome[] = {-1, -1, -1, 0, -1, 1}; | |||
| 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); | ||
| 106 | } | 97 | } |
| 107 | 98 | ||
| 108 | irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS) | 99 | irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS) |
| @@ -117,8 +108,8 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS) | |||
| 117 | 108 | ||
| 118 | status = VIA_READ(VIA_REG_INTERRUPT); | 109 | status = VIA_READ(VIA_REG_INTERRUPT); |
| 119 | if (status & VIA_IRQ_VBLANK_PENDING) { | 110 | if (status & VIA_IRQ_VBLANK_PENDING) { |
| 120 | atomic_inc(&dev_priv->vbl_received); | 111 | atomic_inc(&dev->vbl_received); |
| 121 | if (!(atomic_read(&dev_priv->vbl_received) & 0x0F)) { | 112 | if (!(atomic_read(&dev->vbl_received) & 0x0F)) { |
| 122 | do_gettimeofday(&cur_vblank); | 113 | do_gettimeofday(&cur_vblank); |
| 123 | if (dev_priv->last_vblank_valid) { | 114 | if (dev_priv->last_vblank_valid) { |
| 124 | dev_priv->usec_per_vblank = | 115 | dev_priv->usec_per_vblank = |
| @@ -128,11 +119,12 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS) | |||
| 128 | dev_priv->last_vblank = cur_vblank; | 119 | dev_priv->last_vblank = cur_vblank; |
| 129 | dev_priv->last_vblank_valid = 1; | 120 | dev_priv->last_vblank_valid = 1; |
| 130 | } | 121 | } |
| 131 | if (!(atomic_read(&dev_priv->vbl_received) & 0xFF)) { | 122 | if (!(atomic_read(&dev->vbl_received) & 0xFF)) { |
| 132 | DRM_DEBUG("US per vblank is: %u\n", | 123 | DRM_DEBUG("US per vblank is: %u\n", |
| 133 | dev_priv->usec_per_vblank); | 124 | dev_priv->usec_per_vblank); |
| 134 | } | 125 | } |
| 135 | drm_handle_vblank(dev, 0); | 126 | DRM_WAKEUP(&dev->vbl_queue); |
| 127 | drm_vbl_send_signals(dev); | ||
| 136 | handled = 1; | 128 | handled = 1; |
| 137 | } | 129 | } |
| 138 | 130 | ||
| @@ -171,34 +163,31 @@ static __inline__ void viadrv_acknowledge_irqs(drm_via_private_t * dev_priv) | |||
| 171 | } | 163 | } |
| 172 | } | 164 | } |
| 173 | 165 | ||
| 174 | int via_enable_vblank(struct drm_device *dev, int crtc) | 166 | int via_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence) |
| 175 | { | 167 | { |
| 176 | drm_via_private_t *dev_priv = dev->dev_private; | 168 | drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; |
| 177 | u32 status; | 169 | unsigned int cur_vblank; |
| 170 | int ret = 0; | ||
| 178 | 171 | ||
| 179 | if (crtc != 0) { | 172 | DRM_DEBUG("\n"); |
| 180 | DRM_ERROR("%s: bad crtc %d\n", __FUNCTION__, crtc); | 173 | if (!dev_priv) { |
| 174 | DRM_ERROR("called with no initialization\n"); | ||
| 181 | return -EINVAL; | 175 | return -EINVAL; |
| 182 | } | 176 | } |
| 183 | 177 | ||
| 184 | status = VIA_READ(VIA_REG_INTERRUPT); | 178 | viadrv_acknowledge_irqs(dev_priv); |
| 185 | VIA_WRITE(VIA_REG_INTERRUPT, status & VIA_IRQ_VBLANK_ENABLE); | ||
| 186 | 179 | ||
| 187 | VIA_WRITE8(0x83d4, 0x11); | 180 | /* Assume that the user has missed the current sequence number |
| 188 | VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30); | 181 | * by about a day rather than she wants to wait for years |
| 182 | * using vertical blanks... | ||
| 183 | */ | ||
| 189 | 184 | ||
| 190 | return 0; | 185 | DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, |
| 191 | } | 186 | (((cur_vblank = atomic_read(&dev->vbl_received)) - |
| 187 | *sequence) <= (1 << 23))); | ||
| 192 | 188 | ||
| 193 | void via_disable_vblank(struct drm_device *dev, int crtc) | 189 | *sequence = cur_vblank; |
| 194 | { | 190 | return ret; |
| 195 | drm_via_private_t *dev_priv = dev->dev_private; | ||
| 196 | |||
| 197 | VIA_WRITE8(0x83d4, 0x11); | ||
| 198 | VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) & ~0x30); | ||
| 199 | |||
| 200 | if (crtc != 0) | ||
| 201 | DRM_ERROR("%s: bad crtc %d\n", __FUNCTION__, crtc); | ||
| 202 | } | 191 | } |
| 203 | 192 | ||
| 204 | static int | 193 | static int |
| @@ -303,25 +292,23 @@ void via_driver_irq_preinstall(struct drm_device * dev) | |||
| 303 | } | 292 | } |
| 304 | } | 293 | } |
| 305 | 294 | ||
| 306 | int via_driver_irq_postinstall(struct drm_device * dev) | 295 | void via_driver_irq_postinstall(struct drm_device * dev) |
| 307 | { | 296 | { |
| 308 | drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; | 297 | drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; |
| 309 | u32 status; | 298 | u32 status; |
| 310 | 299 | ||
| 311 | DRM_DEBUG("via_driver_irq_postinstall\n"); | 300 | DRM_DEBUG("\n"); |
| 312 | if (!dev_priv) | 301 | if (dev_priv) { |
| 313 | return -EINVAL; | 302 | status = VIA_READ(VIA_REG_INTERRUPT); |
| 303 | VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL | ||
| 304 | | dev_priv->irq_enable_mask); | ||
| 314 | 305 | ||
| 315 | drm_vblank_init(dev, 1); | 306 | /* Some magic, oh for some data sheets ! */ |
| 316 | status = VIA_READ(VIA_REG_INTERRUPT); | ||
| 317 | VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL | ||
| 318 | | dev_priv->irq_enable_mask); | ||
| 319 | 307 | ||
| 320 | /* Some magic, oh for some data sheets ! */ | 308 | VIA_WRITE8(0x83d4, 0x11); |
| 321 | VIA_WRITE8(0x83d4, 0x11); | 309 | VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30); |
| 322 | VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30); | ||
| 323 | 310 | ||
| 324 | return 0; | 311 | } |
| 325 | } | 312 | } |
| 326 | 313 | ||
| 327 | void via_driver_irq_uninstall(struct drm_device * dev) | 314 | void via_driver_irq_uninstall(struct drm_device * dev) |
