From 0acce24b3c9caf80bad270dd1a4994f1486c266d Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Mon, 12 Jan 2009 17:41:01 +0000 Subject: Drop linux-moblin obsolete kernels --- .../0011-drm-vblank-rework.patch | 1534 -------------------- 1 file changed, 1534 deletions(-) delete mode 100644 meta-moblin/packages/linux/linux-moblin-2.6.27-rc6/0011-drm-vblank-rework.patch (limited to 'meta-moblin/packages/linux/linux-moblin-2.6.27-rc6/0011-drm-vblank-rework.patch') diff --git a/meta-moblin/packages/linux/linux-moblin-2.6.27-rc6/0011-drm-vblank-rework.patch b/meta-moblin/packages/linux/linux-moblin-2.6.27-rc6/0011-drm-vblank-rework.patch deleted file mode 100644 index 6161a71f0..000000000 --- a/meta-moblin/packages/linux/linux-moblin-2.6.27-rc6/0011-drm-vblank-rework.patch +++ /dev/null @@ -1,1534 +0,0 @@ -commit 2aebb4e4e62d09b4a95be7be7c24a7f6528385b7 -Author: Jesse Barnes -Date: Tue Sep 30 12:14:26 2008 -0700 - - drm: Rework vblank-wait handling to allow interrupt reduction. - - Previously, drivers supporting vblank interrupt waits would run the interrupt - all the time, or all the time that any 3d client was running, preventing the - CPU from sleeping for long when the system was otherwise idle. Now, interrupts - are disabled any time that no client is waiting on a vblank event. The new - method uses vblank counters on the chipsets when the interrupts are turned - off, rather than counting interrupts, so that we can continue to present - accurate vblank numbers. - - Co-author: Michel Dänzer - Signed-off-by: Jesse Barnes - Signed-off-by: Eric Anholt - Signed-off-by: Dave Airlie - -diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c -index 452c2d8..fb45fe7 100644 ---- a/drivers/gpu/drm/drm_drv.c -+++ b/drivers/gpu/drm/drm_drv.c -@@ -116,6 +116,8 @@ static struct drm_ioctl_desc drm_ioctls[] = { - - DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank, 0), - -+ DRM_IOCTL_DEF(DRM_IOCTL_MODESET_CTL, drm_modeset_ctl, 0), -+ - DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - }; - -diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c -index 61ed515..d0c13d9 100644 ---- a/drivers/gpu/drm/drm_irq.c -+++ b/drivers/gpu/drm/drm_irq.c -@@ -71,19 +71,131 @@ int drm_irq_by_busid(struct drm_device *dev, void *data, - return 0; - } - -+static void vblank_disable_fn(unsigned long arg) -+{ -+ struct drm_device *dev = (struct drm_device *)arg; -+ unsigned long irqflags; -+ int i; -+ -+ if (!dev->vblank_disable_allowed) -+ return; -+ -+ for (i = 0; i < dev->num_crtcs; i++) { -+ spin_lock_irqsave(&dev->vbl_lock, irqflags); -+ if (atomic_read(&dev->vblank_refcount[i]) == 0 && -+ dev->vblank_enabled[i]) { -+ DRM_DEBUG("disabling vblank on crtc %d\n", i); -+ dev->last_vblank[i] = -+ dev->driver->get_vblank_counter(dev, i); -+ dev->driver->disable_vblank(dev, i); -+ dev->vblank_enabled[i] = 0; -+ } -+ spin_unlock_irqrestore(&dev->vbl_lock, irqflags); -+ } -+} -+ -+static void drm_vblank_cleanup(struct drm_device *dev) -+{ -+ /* Bail if the driver didn't call drm_vblank_init() */ -+ if (dev->num_crtcs == 0) -+ return; -+ -+ del_timer(&dev->vblank_disable_timer); -+ -+ vblank_disable_fn((unsigned long)dev); -+ -+ drm_free(dev->vbl_queue, sizeof(*dev->vbl_queue) * dev->num_crtcs, -+ DRM_MEM_DRIVER); -+ drm_free(dev->vbl_sigs, sizeof(*dev->vbl_sigs) * dev->num_crtcs, -+ DRM_MEM_DRIVER); -+ drm_free(dev->_vblank_count, sizeof(*dev->_vblank_count) * -+ dev->num_crtcs, DRM_MEM_DRIVER); -+ drm_free(dev->vblank_refcount, sizeof(*dev->vblank_refcount) * -+ dev->num_crtcs, DRM_MEM_DRIVER); -+ drm_free(dev->vblank_enabled, sizeof(*dev->vblank_enabled) * -+ dev->num_crtcs, DRM_MEM_DRIVER); -+ drm_free(dev->last_vblank, sizeof(*dev->last_vblank) * dev->num_crtcs, -+ DRM_MEM_DRIVER); -+ drm_free(dev->vblank_inmodeset, sizeof(*dev->vblank_inmodeset) * -+ dev->num_crtcs, DRM_MEM_DRIVER); -+ -+ dev->num_crtcs = 0; -+} -+ -+int drm_vblank_init(struct drm_device *dev, int num_crtcs) -+{ -+ int i, ret = -ENOMEM; -+ -+ setup_timer(&dev->vblank_disable_timer, vblank_disable_fn, -+ (unsigned long)dev); -+ spin_lock_init(&dev->vbl_lock); -+ atomic_set(&dev->vbl_signal_pending, 0); -+ dev->num_crtcs = num_crtcs; -+ -+ dev->vbl_queue = drm_alloc(sizeof(wait_queue_head_t) * num_crtcs, -+ DRM_MEM_DRIVER); -+ if (!dev->vbl_queue) -+ goto err; -+ -+ dev->vbl_sigs = drm_alloc(sizeof(struct list_head) * num_crtcs, -+ DRM_MEM_DRIVER); -+ if (!dev->vbl_sigs) -+ goto err; -+ -+ dev->_vblank_count = drm_alloc(sizeof(atomic_t) * num_crtcs, -+ DRM_MEM_DRIVER); -+ if (!dev->_vblank_count) -+ goto err; -+ -+ dev->vblank_refcount = drm_alloc(sizeof(atomic_t) * num_crtcs, -+ DRM_MEM_DRIVER); -+ if (!dev->vblank_refcount) -+ goto err; -+ -+ dev->vblank_enabled = drm_calloc(num_crtcs, sizeof(int), -+ DRM_MEM_DRIVER); -+ if (!dev->vblank_enabled) -+ goto err; -+ -+ dev->last_vblank = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER); -+ if (!dev->last_vblank) -+ goto err; -+ -+ dev->vblank_inmodeset = drm_calloc(num_crtcs, sizeof(int), -+ DRM_MEM_DRIVER); -+ if (!dev->vblank_inmodeset) -+ goto err; -+ -+ /* Zero per-crtc vblank stuff */ -+ for (i = 0; i < num_crtcs; i++) { -+ init_waitqueue_head(&dev->vbl_queue[i]); -+ INIT_LIST_HEAD(&dev->vbl_sigs[i]); -+ atomic_set(&dev->_vblank_count[i], 0); -+ atomic_set(&dev->vblank_refcount[i], 0); -+ } -+ -+ dev->vblank_disable_allowed = 0; -+ -+ return 0; -+ -+err: -+ drm_vblank_cleanup(dev); -+ return ret; -+} -+EXPORT_SYMBOL(drm_vblank_init); -+ - /** - * Install IRQ handler. - * - * \param dev DRM device. -- * \param irq IRQ number. - * -- * Initializes the IRQ related data, and setups drm_device::vbl_queue. Installs the handler, calling the driver -+ * Initializes the IRQ related data. Installs the handler, calling the driver - * \c drm_driver_irq_preinstall() and \c drm_driver_irq_postinstall() functions - * before and after the installation. - */ --static int drm_irq_install(struct drm_device * dev) -+int drm_irq_install(struct drm_device *dev) - { -- int ret; -+ int ret = 0; - unsigned long sh_flags = 0; - - if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) -@@ -109,17 +221,6 @@ static int drm_irq_install(struct drm_device * dev) - - DRM_DEBUG("irq=%d\n", dev->pdev->irq); - -- if (drm_core_check_feature(dev, DRIVER_IRQ_VBL)) { -- init_waitqueue_head(&dev->vbl_queue); -- -- spin_lock_init(&dev->vbl_lock); -- -- INIT_LIST_HEAD(&dev->vbl_sigs); -- INIT_LIST_HEAD(&dev->vbl_sigs2); -- -- dev->vbl_pending = 0; -- } -- - /* Before installing handler */ - dev->driver->irq_preinstall(dev); - -@@ -141,10 +242,16 @@ static int drm_irq_install(struct drm_device * dev) - } - - /* After installing handler */ -- dev->driver->irq_postinstall(dev); -+ ret = dev->driver->irq_postinstall(dev); -+ if (ret < 0) { -+ mutex_lock(&dev->struct_mutex); -+ dev->irq_enabled = 0; -+ mutex_unlock(&dev->struct_mutex); -+ } - -- return 0; -+ return ret; - } -+EXPORT_SYMBOL(drm_irq_install); - - /** - * Uninstall the IRQ handler. -@@ -174,11 +281,12 @@ int drm_irq_uninstall(struct drm_device * dev) - - free_irq(dev->pdev->irq, dev); - -+ drm_vblank_cleanup(dev); -+ - dev->locked_tasklet_func = NULL; - - return 0; - } -- - EXPORT_SYMBOL(drm_irq_uninstall); - - /** -@@ -218,6 +326,174 @@ int drm_control(struct drm_device *dev, void *data, - } - - /** -+ * drm_vblank_count - retrieve "cooked" vblank counter value -+ * @dev: DRM device -+ * @crtc: which counter to retrieve -+ * -+ * Fetches the "cooked" vblank count value that represents the number of -+ * vblank events since the system was booted, including lost events due to -+ * modesetting activity. -+ */ -+u32 drm_vblank_count(struct drm_device *dev, int crtc) -+{ -+ return atomic_read(&dev->_vblank_count[crtc]); -+} -+EXPORT_SYMBOL(drm_vblank_count); -+ -+/** -+ * drm_update_vblank_count - update the master vblank counter -+ * @dev: DRM device -+ * @crtc: counter to update -+ * -+ * Call back into the driver to update the appropriate vblank counter -+ * (specified by @crtc). Deal with wraparound, if it occurred, and -+ * update the last read value so we can deal with wraparound on the next -+ * call if necessary. -+ * -+ * Only necessary when going from off->on, to account for frames we -+ * didn't get an interrupt for. -+ * -+ * Note: caller must hold dev->vbl_lock since this reads & writes -+ * device vblank fields. -+ */ -+static void drm_update_vblank_count(struct drm_device *dev, int crtc) -+{ -+ u32 cur_vblank, diff; -+ -+ /* -+ * Interrupts were disabled prior to this call, so deal with counter -+ * wrap if needed. -+ * NOTE! It's possible we lost a full dev->max_vblank_count events -+ * here if the register is small or we had vblank interrupts off for -+ * a long time. -+ */ -+ cur_vblank = dev->driver->get_vblank_counter(dev, crtc); -+ diff = cur_vblank - dev->last_vblank[crtc]; -+ if (cur_vblank < dev->last_vblank[crtc]) { -+ diff += dev->max_vblank_count; -+ -+ DRM_DEBUG("last_vblank[%d]=0x%x, cur_vblank=0x%x => diff=0x%x\n", -+ crtc, dev->last_vblank[crtc], cur_vblank, diff); -+ } -+ -+ DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n", -+ crtc, diff); -+ -+ atomic_add(diff, &dev->_vblank_count[crtc]); -+} -+ -+/** -+ * drm_vblank_get - get a reference count on vblank events -+ * @dev: DRM device -+ * @crtc: which CRTC to own -+ * -+ * Acquire a reference count on vblank events to avoid having them disabled -+ * while in use. -+ * -+ * RETURNS -+ * Zero on success, nonzero on failure. -+ */ -+int drm_vblank_get(struct drm_device *dev, int crtc) -+{ -+ unsigned long irqflags; -+ int ret = 0; -+ -+ spin_lock_irqsave(&dev->vbl_lock, irqflags); -+ /* Going from 0->1 means we have to enable interrupts again */ -+ if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1 && -+ !dev->vblank_enabled[crtc]) { -+ ret = dev->driver->enable_vblank(dev, crtc); -+ DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", crtc, ret); -+ if (ret) -+ atomic_dec(&dev->vblank_refcount[crtc]); -+ else { -+ dev->vblank_enabled[crtc] = 1; -+ drm_update_vblank_count(dev, crtc); -+ } -+ } -+ spin_unlock_irqrestore(&dev->vbl_lock, irqflags); -+ -+ return ret; -+} -+EXPORT_SYMBOL(drm_vblank_get); -+ -+/** -+ * drm_vblank_put - give up ownership of vblank events -+ * @dev: DRM device -+ * @crtc: which counter to give up -+ * -+ * Release ownership of a given vblank counter, turning off interrupts -+ * if possible. -+ */ -+void drm_vblank_put(struct drm_device *dev, int crtc) -+{ -+ /* Last user schedules interrupt disable */ -+ if (atomic_dec_and_test(&dev->vblank_refcount[crtc])) -+ mod_timer(&dev->vblank_disable_timer, jiffies + 5*DRM_HZ); -+} -+EXPORT_SYMBOL(drm_vblank_put); -+ -+/** -+ * drm_modeset_ctl - handle vblank event counter changes across mode switch -+ * @DRM_IOCTL_ARGS: standard ioctl arguments -+ * -+ * Applications should call the %_DRM_PRE_MODESET and %_DRM_POST_MODESET -+ * ioctls around modesetting so that any lost vblank events are accounted for. -+ * -+ * Generally the counter will reset across mode sets. If interrupts are -+ * enabled around this call, we don't have to do anything since the counter -+ * will have already been incremented. -+ */ -+int drm_modeset_ctl(struct drm_device *dev, void *data, -+ struct drm_file *file_priv) -+{ -+ struct drm_modeset_ctl *modeset = data; -+ unsigned long irqflags; -+ int crtc, ret = 0; -+ -+ /* If drm_vblank_init() hasn't been called yet, just no-op */ -+ if (!dev->num_crtcs) -+ goto out; -+ -+ crtc = modeset->crtc; -+ if (crtc >= dev->num_crtcs) { -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ /* -+ * To avoid all the problems that might happen if interrupts -+ * were enabled/disabled around or between these calls, we just -+ * have the kernel take a reference on the CRTC (just once though -+ * to avoid corrupting the count if multiple, mismatch calls occur), -+ * so that interrupts remain enabled in the interim. -+ */ -+ switch (modeset->cmd) { -+ case _DRM_PRE_MODESET: -+ if (!dev->vblank_inmodeset[crtc]) { -+ dev->vblank_inmodeset[crtc] = 1; -+ drm_vblank_get(dev, crtc); -+ } -+ break; -+ case _DRM_POST_MODESET: -+ if (dev->vblank_inmodeset[crtc]) { -+ spin_lock_irqsave(&dev->vbl_lock, irqflags); -+ dev->vblank_disable_allowed = 1; -+ dev->vblank_inmodeset[crtc] = 0; -+ spin_unlock_irqrestore(&dev->vbl_lock, irqflags); -+ drm_vblank_put(dev, crtc); -+ } -+ break; -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ -+out: -+ return ret; -+} -+ -+/** - * Wait for VBLANK. - * - * \param inode device inode. -@@ -236,12 +512,12 @@ int drm_control(struct drm_device *dev, void *data, - * - * If a signal is not requested, then calls vblank_wait(). - */ --int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv) -+int drm_wait_vblank(struct drm_device *dev, void *data, -+ struct drm_file *file_priv) - { - union drm_wait_vblank *vblwait = data; -- struct timeval now; - int ret = 0; -- unsigned int flags, seq; -+ unsigned int flags, seq, crtc; - - if ((!dev->pdev->irq) || (!dev->irq_enabled)) - return -EINVAL; -@@ -255,13 +531,17 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr - } - - flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK; -+ crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0; - -- if (!drm_core_check_feature(dev, (flags & _DRM_VBLANK_SECONDARY) ? -- DRIVER_IRQ_VBL2 : DRIVER_IRQ_VBL)) -+ if (crtc >= dev->num_crtcs) - return -EINVAL; - -- seq = atomic_read((flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2 -- : &dev->vbl_received); -+ ret = drm_vblank_get(dev, crtc); -+ if (ret) { -+ DRM_ERROR("failed to acquire vblank counter, %d\n", ret); -+ return ret; -+ } -+ seq = drm_vblank_count(dev, crtc); - - switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) { - case _DRM_VBLANK_RELATIVE: -@@ -270,7 +550,8 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr - case _DRM_VBLANK_ABSOLUTE: - break; - default: -- return -EINVAL; -+ ret = -EINVAL; -+ goto done; - } - - if ((flags & _DRM_VBLANK_NEXTONMISS) && -@@ -280,8 +561,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr - - if (flags & _DRM_VBLANK_SIGNAL) { - unsigned long irqflags; -- struct list_head *vbl_sigs = (flags & _DRM_VBLANK_SECONDARY) -- ? &dev->vbl_sigs2 : &dev->vbl_sigs; -+ struct list_head *vbl_sigs = &dev->vbl_sigs[crtc]; - struct drm_vbl_sig *vbl_sig; - - spin_lock_irqsave(&dev->vbl_lock, irqflags); -@@ -302,22 +582,29 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr - } - } - -- if (dev->vbl_pending >= 100) { -+ if (atomic_read(&dev->vbl_signal_pending) >= 100) { - spin_unlock_irqrestore(&dev->vbl_lock, irqflags); -- return -EBUSY; -+ ret = -EBUSY; -+ goto done; - } - -- dev->vbl_pending++; -- - spin_unlock_irqrestore(&dev->vbl_lock, irqflags); - -- if (! -- (vbl_sig = -- drm_alloc(sizeof(struct drm_vbl_sig), DRM_MEM_DRIVER))) { -- return -ENOMEM; -+ vbl_sig = drm_calloc(1, sizeof(struct drm_vbl_sig), -+ DRM_MEM_DRIVER); -+ if (!vbl_sig) { -+ ret = -ENOMEM; -+ goto done; -+ } -+ -+ ret = drm_vblank_get(dev, crtc); -+ if (ret) { -+ drm_free(vbl_sig, sizeof(struct drm_vbl_sig), -+ DRM_MEM_DRIVER); -+ return ret; - } - -- memset((void *)vbl_sig, 0, sizeof(*vbl_sig)); -+ atomic_inc(&dev->vbl_signal_pending); - - vbl_sig->sequence = vblwait->request.sequence; - vbl_sig->info.si_signo = vblwait->request.signal; -@@ -331,20 +618,29 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr - - vblwait->reply.sequence = seq; - } else { -- if (flags & _DRM_VBLANK_SECONDARY) { -- if (dev->driver->vblank_wait2) -- ret = dev->driver->vblank_wait2(dev, &vblwait->request.sequence); -- } else if (dev->driver->vblank_wait) -- ret = -- dev->driver->vblank_wait(dev, -- &vblwait->request.sequence); -- -- do_gettimeofday(&now); -- vblwait->reply.tval_sec = now.tv_sec; -- vblwait->reply.tval_usec = now.tv_usec; -+ DRM_DEBUG("waiting on vblank count %d, crtc %d\n", -+ vblwait->request.sequence, crtc); -+ DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ, -+ ((drm_vblank_count(dev, crtc) -+ - vblwait->request.sequence) <= (1 << 23))); -+ -+ if (ret != -EINTR) { -+ struct timeval now; -+ -+ do_gettimeofday(&now); -+ -+ vblwait->reply.tval_sec = now.tv_sec; -+ vblwait->reply.tval_usec = now.tv_usec; -+ vblwait->reply.sequence = drm_vblank_count(dev, crtc); -+ DRM_DEBUG("returning %d to client\n", -+ vblwait->reply.sequence); -+ } else { -+ DRM_DEBUG("vblank wait interrupted by signal\n"); -+ } - } - -- done: -+done: -+ drm_vblank_put(dev, crtc); - return ret; - } - -@@ -352,44 +648,57 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr - * Send the VBLANK signals. - * - * \param dev DRM device. -+ * \param crtc CRTC where the vblank event occurred - * - * Sends a signal for each task in drm_device::vbl_sigs and empties the list. - * - * If a signal is not requested, then calls vblank_wait(). - */ --void drm_vbl_send_signals(struct drm_device * dev) -+static void drm_vbl_send_signals(struct drm_device *dev, int crtc) - { -+ struct drm_vbl_sig *vbl_sig, *tmp; -+ struct list_head *vbl_sigs; -+ unsigned int vbl_seq; - unsigned long flags; -- int i; - - spin_lock_irqsave(&dev->vbl_lock, flags); - -- for (i = 0; i < 2; i++) { -- struct drm_vbl_sig *vbl_sig, *tmp; -- struct list_head *vbl_sigs = i ? &dev->vbl_sigs2 : &dev->vbl_sigs; -- unsigned int vbl_seq = atomic_read(i ? &dev->vbl_received2 : -- &dev->vbl_received); -+ vbl_sigs = &dev->vbl_sigs[crtc]; -+ vbl_seq = drm_vblank_count(dev, crtc); - -- list_for_each_entry_safe(vbl_sig, tmp, vbl_sigs, head) { -- if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) { -- vbl_sig->info.si_code = vbl_seq; -- send_sig_info(vbl_sig->info.si_signo, -- &vbl_sig->info, vbl_sig->task); -+ list_for_each_entry_safe(vbl_sig, tmp, vbl_sigs, head) { -+ if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) { -+ vbl_sig->info.si_code = vbl_seq; -+ send_sig_info(vbl_sig->info.si_signo, -+ &vbl_sig->info, vbl_sig->task); - -- list_del(&vbl_sig->head); -- -- drm_free(vbl_sig, sizeof(*vbl_sig), -- DRM_MEM_DRIVER); -+ list_del(&vbl_sig->head); - -- dev->vbl_pending--; -- } -- } -+ drm_free(vbl_sig, sizeof(*vbl_sig), -+ DRM_MEM_DRIVER); -+ atomic_dec(&dev->vbl_signal_pending); -+ drm_vblank_put(dev, crtc); -+ } - } - - spin_unlock_irqrestore(&dev->vbl_lock, flags); - } - --EXPORT_SYMBOL(drm_vbl_send_signals); -+/** -+ * drm_handle_vblank - handle a vblank event -+ * @dev: DRM device -+ * @crtc: where this event occurred -+ * -+ * Drivers should call this routine in their vblank interrupt handlers to -+ * update the vblank counter and send any signals that may be pending. -+ */ -+void drm_handle_vblank(struct drm_device *dev, int crtc) -+{ -+ atomic_inc(&dev->_vblank_count[crtc]); -+ DRM_WAKEUP(&dev->vbl_queue[crtc]); -+ drm_vbl_send_signals(dev, crtc); -+} -+EXPORT_SYMBOL(drm_handle_vblank); - - /** - * Tasklet wrapper function. -diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c -index cead62f..8609ec2 100644 ---- a/drivers/gpu/drm/i915/i915_dma.c -+++ b/drivers/gpu/drm/i915/i915_dma.c -@@ -673,7 +673,7 @@ static int i915_getparam(struct drm_device *dev, void *data, - - switch (param->param) { - case I915_PARAM_IRQ_ACTIVE: -- value = dev->irq_enabled; -+ value = dev->pdev->irq ? 1 : 0; - break; - case I915_PARAM_ALLOW_BATCHBUFFER: - value = dev_priv->allow_batchbuffer ? 1 : 0; -@@ -808,7 +808,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) - * and the registers being closely associated. - */ - if (!IS_I945G(dev) && !IS_I945GM(dev)) -- pci_enable_msi(dev->pdev); -+ if (pci_enable_msi(dev->pdev)) -+ DRM_ERROR("failed to enable MSI\n"); - - intel_opregion_init(dev); - -diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c -index eff66ed..37af03f 100644 ---- a/drivers/gpu/drm/i915/i915_drv.c -+++ b/drivers/gpu/drm/i915/i915_drv.c -@@ -85,10 +85,8 @@ static struct drm_driver driver = { - /* don't use mtrr's here, the Xserver or user space app should - * deal with them for intel hardware. - */ -- .driver_features = -- DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | /* DRIVER_USE_MTRR |*/ -- DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL | -- DRIVER_IRQ_VBL2, -+ .driver_features = DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | -+ DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED, - .load = i915_driver_load, - .unload = i915_driver_unload, - .lastclose = i915_driver_lastclose, -@@ -96,8 +94,9 @@ static struct drm_driver driver = { - .suspend = i915_suspend, - .resume = i915_resume, - .device_is_agp = i915_driver_device_is_agp, -- .vblank_wait = i915_driver_vblank_wait, -- .vblank_wait2 = i915_driver_vblank_wait2, -+ .get_vblank_counter = i915_get_vblank_counter, -+ .enable_vblank = i915_enable_vblank, -+ .disable_vblank = i915_disable_vblank, - .irq_preinstall = i915_driver_irq_preinstall, - .irq_postinstall = i915_driver_irq_postinstall, - .irq_uninstall = i915_driver_irq_uninstall, -diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h -index 71326ca..d1a02be 100644 ---- a/drivers/gpu/drm/i915/i915_drv.h -+++ b/drivers/gpu/drm/i915/i915_drv.h -@@ -83,10 +83,15 @@ struct mem_block { - typedef struct _drm_i915_vbl_swap { - struct list_head head; - drm_drawable_t drw_id; -- unsigned int pipe; -+ unsigned int plane; - unsigned int sequence; - } drm_i915_vbl_swap_t; - -+struct opregion_header; -+struct opregion_acpi; -+struct opregion_swsci; -+struct opregion_asle; -+ - struct intel_opregion { - struct opregion_header *header; - struct opregion_acpi *acpi; -@@ -105,7 +110,7 @@ typedef struct drm_i915_private { - drm_dma_handle_t *status_page_dmah; - void *hw_status_page; - dma_addr_t dma_status_page; -- unsigned long counter; -+ uint32_t counter; - unsigned int status_gfx_addr; - drm_local_map_t hws_map; - -@@ -247,16 +252,17 @@ extern int i915_irq_emit(struct drm_device *dev, void *data, - extern int i915_irq_wait(struct drm_device *dev, void *data, - struct drm_file *file_priv); - --extern int i915_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence); --extern int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence); - extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS); - extern void i915_driver_irq_preinstall(struct drm_device * dev); --extern void i915_driver_irq_postinstall(struct drm_device * dev); -+extern int i915_driver_irq_postinstall(struct drm_device *dev); - extern void i915_driver_irq_uninstall(struct drm_device * dev); - extern int i915_vblank_pipe_set(struct drm_device *dev, void *data, - struct drm_file *file_priv); - extern int i915_vblank_pipe_get(struct drm_device *dev, void *data, - struct drm_file *file_priv); -+extern int i915_enable_vblank(struct drm_device *dev, int crtc); -+extern void i915_disable_vblank(struct drm_device *dev, int crtc); -+extern u32 i915_get_vblank_counter(struct drm_device *dev, int crtc); - extern int i915_vblank_swap(struct drm_device *dev, void *data, - struct drm_file *file_priv); - extern void i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask); -@@ -278,6 +284,10 @@ extern void i915_mem_release(struct drm_device * dev, - extern int i915_save_state(struct drm_device *dev); - extern int i915_restore_state(struct drm_device *dev); - -+/* i915_suspend.c */ -+extern int i915_save_state(struct drm_device *dev); -+extern int i915_restore_state(struct drm_device *dev); -+ - /* i915_opregion.c */ - extern int intel_opregion_init(struct drm_device *dev); - extern void intel_opregion_free(struct drm_device *dev); -diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c -index ae7d3a8..f875959 100644 ---- a/drivers/gpu/drm/i915/i915_irq.c -+++ b/drivers/gpu/drm/i915/i915_irq.c -@@ -35,9 +35,8 @@ - - /** These are the interrupts used by the driver */ - #define I915_INTERRUPT_ENABLE_MASK (I915_USER_INTERRUPT | \ -- I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT | \ -- I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT | \ - I915_ASLE_INTERRUPT | \ -+ I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | \ - I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) - - void -@@ -61,6 +60,64 @@ i915_disable_irq(drm_i915_private_t *dev_priv, u32 mask) - } - - /** -+ * i915_get_pipe - return the the pipe associated with a given plane -+ * @dev: DRM device -+ * @plane: plane to look for -+ * -+ * The Intel Mesa & 2D drivers call the vblank routines with a plane number -+ * rather than a pipe number, since they may not always be equal. This routine -+ * maps the given @plane back to a pipe number. -+ */ -+static int -+i915_get_pipe(struct drm_device *dev, int plane) -+{ -+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; -+ u32 dspcntr; -+ -+ dspcntr = plane ? I915_READ(DSPBCNTR) : I915_READ(DSPACNTR); -+ -+ return dspcntr & DISPPLANE_SEL_PIPE_MASK ? 1 : 0; -+} -+ -+/** -+ * i915_get_plane - return the the plane associated with a given pipe -+ * @dev: DRM device -+ * @pipe: pipe to look for -+ * -+ * The Intel Mesa & 2D drivers call the vblank routines with a plane number -+ * rather than a plane number, since they may not always be equal. This routine -+ * maps the given @pipe back to a plane number. -+ */ -+static int -+i915_get_plane(struct drm_device *dev, int pipe) -+{ -+ if (i915_get_pipe(dev, 0) == pipe) -+ return 0; -+ return 1; -+} -+ -+/** -+ * i915_pipe_enabled - check if a pipe is enabled -+ * @dev: DRM device -+ * @pipe: pipe to check -+ * -+ * Reading certain registers when the pipe is disabled can hang the chip. -+ * Use this routine to make sure the PLL is running and the pipe is active -+ * before reading such registers if unsure. -+ */ -+static int -+i915_pipe_enabled(struct drm_device *dev, int pipe) -+{ -+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; -+ unsigned long pipeconf = pipe ? PIPEBCONF : PIPEACONF; -+ -+ if (I915_READ(pipeconf) & PIPEACONF_ENABLE) -+ return 1; -+ -+ return 0; -+} -+ -+/** - * Emit blits for scheduled buffer swaps. - * - * This function will be called with the HW lock held. -@@ -71,8 +128,7 @@ static void i915_vblank_tasklet(struct drm_device *dev) - unsigned long irqflags; - struct list_head *list, *tmp, hits, *hit; - int nhits, nrects, slice[2], upper[2], lower[2], i; -- unsigned counter[2] = { atomic_read(&dev->vbl_received), -- atomic_read(&dev->vbl_received2) }; -+ unsigned counter[2]; - struct drm_drawable_info *drw; - drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; - u32 cpp = dev_priv->cpp; -@@ -94,6 +150,9 @@ static void i915_vblank_tasklet(struct drm_device *dev) - src_pitch >>= 2; - } - -+ counter[0] = drm_vblank_count(dev, 0); -+ counter[1] = drm_vblank_count(dev, 1); -+ - DRM_DEBUG("\n"); - - INIT_LIST_HEAD(&hits); -@@ -106,12 +165,14 @@ static void i915_vblank_tasklet(struct drm_device *dev) - list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) { - drm_i915_vbl_swap_t *vbl_swap = - list_entry(list, drm_i915_vbl_swap_t, head); -+ int pipe = i915_get_pipe(dev, vbl_swap->plane); - -- if ((counter[vbl_swap->pipe] - vbl_swap->sequence) > (1<<23)) -+ if ((counter[pipe] - vbl_swap->sequence) > (1<<23)) - continue; - - list_del(list); - dev_priv->swaps_pending--; -+ drm_vblank_put(dev, pipe); - - spin_unlock(&dev_priv->swaps_lock); - spin_lock(&dev->drw_lock); -@@ -204,7 +265,7 @@ static void i915_vblank_tasklet(struct drm_device *dev) - drm_i915_vbl_swap_t *swap_hit = - list_entry(hit, drm_i915_vbl_swap_t, head); - struct drm_clip_rect *rect; -- int num_rects, pipe; -+ int num_rects, plane; - unsigned short top, bottom; - - drw = drm_get_drawable_info(dev, swap_hit->drw_id); -@@ -213,9 +274,9 @@ static void i915_vblank_tasklet(struct drm_device *dev) - continue; - - rect = drw->rects; -- pipe = swap_hit->pipe; -- top = upper[pipe]; -- bottom = lower[pipe]; -+ plane = swap_hit->plane; -+ top = upper[plane]; -+ bottom = lower[plane]; - - for (num_rects = drw->num_rects; num_rects--; rect++) { - int y1 = max(rect->y1, top); -@@ -252,22 +313,54 @@ static void i915_vblank_tasklet(struct drm_device *dev) - } - } - -+u32 i915_get_vblank_counter(struct drm_device *dev, int plane) -+{ -+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; -+ unsigned long high_frame; -+ unsigned long low_frame; -+ u32 high1, high2, low, count; -+ int pipe; -+ -+ pipe = i915_get_pipe(dev, plane); -+ high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH; -+ low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL; -+ -+ if (!i915_pipe_enabled(dev, pipe)) { -+ DRM_ERROR("trying to get vblank count for disabled pipe %d\n", pipe); -+ return 0; -+ } -+ -+ /* -+ * High & low register fields aren't synchronized, so make sure -+ * we get a low value that's stable across two reads of the high -+ * register. -+ */ -+ do { -+ high1 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >> -+ PIPE_FRAME_HIGH_SHIFT); -+ low = ((I915_READ(low_frame) & PIPE_FRAME_LOW_MASK) >> -+ PIPE_FRAME_LOW_SHIFT); -+ high2 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >> -+ PIPE_FRAME_HIGH_SHIFT); -+ } while (high1 != high2); -+ -+ count = (high1 << 8) | low; -+ -+ return count; -+} -+ - irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) - { - struct drm_device *dev = (struct drm_device *) arg; - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; -- u32 pipea_stats, pipeb_stats; - u32 iir; -- -- pipea_stats = I915_READ(PIPEASTAT); -- pipeb_stats = I915_READ(PIPEBSTAT); -+ u32 pipea_stats, pipeb_stats; -+ int vblank = 0; - - if (dev->pdev->msi_enabled) - I915_WRITE(IMR, ~0); - iir = I915_READ(IIR); - -- DRM_DEBUG("iir=%08x\n", iir); -- - if (iir == 0) { - if (dev->pdev->msi_enabled) { - I915_WRITE(IMR, dev_priv->irq_mask_reg); -@@ -276,48 +369,56 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) - return IRQ_NONE; - } - -- I915_WRITE(PIPEASTAT, pipea_stats); -- I915_WRITE(PIPEBSTAT, pipeb_stats); -- -- I915_WRITE(IIR, iir); -- if (dev->pdev->msi_enabled) -- I915_WRITE(IMR, dev_priv->irq_mask_reg); -- (void) I915_READ(IIR); /* Flush posted writes */ -- -- dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); -- -- if (iir & I915_USER_INTERRUPT) -- DRM_WAKEUP(&dev_priv->irq_queue); -- -- if (iir & (I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT | -- I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT)) { -- int vblank_pipe = dev_priv->vblank_pipe; -- -- if ((vblank_pipe & -- (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) -- == (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) { -- if (iir & I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT) -- atomic_inc(&dev->vbl_received); -- if (iir & I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT) -- atomic_inc(&dev->vbl_received2); -- } else if (((iir & I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT) && -- (vblank_pipe & DRM_I915_VBLANK_PIPE_A)) || -- ((iir & I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT) && -- (vblank_pipe & DRM_I915_VBLANK_PIPE_B))) -- atomic_inc(&dev->vbl_received); -+ /* -+ * Clear the PIPE(A|B)STAT regs before the IIR otherwise -+ * we may get extra interrupts. -+ */ -+ if (iir & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) { -+ pipea_stats = I915_READ(PIPEASTAT); -+ if (!(dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A)) -+ pipea_stats &= ~(PIPE_START_VBLANK_INTERRUPT_ENABLE | -+ PIPE_VBLANK_INTERRUPT_ENABLE); -+ else if (pipea_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS| -+ PIPE_VBLANK_INTERRUPT_STATUS)) { -+ vblank++; -+ drm_handle_vblank(dev, i915_get_plane(dev, 0)); -+ } - -- DRM_WAKEUP(&dev->vbl_queue); -- drm_vbl_send_signals(dev); -+ I915_WRITE(PIPEASTAT, pipea_stats); -+ } -+ if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) { -+ pipeb_stats = I915_READ(PIPEBSTAT); -+ /* Ack the event */ -+ I915_WRITE(PIPEBSTAT, pipeb_stats); -+ -+ /* The vblank interrupt gets enabled even if we didn't ask for -+ it, so make sure it's shut down again */ -+ if (!(dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B)) -+ pipeb_stats &= ~(PIPE_START_VBLANK_INTERRUPT_ENABLE | -+ PIPE_VBLANK_INTERRUPT_ENABLE); -+ else if (pipeb_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS| -+ PIPE_VBLANK_INTERRUPT_STATUS)) { -+ vblank++; -+ drm_handle_vblank(dev, i915_get_plane(dev, 1)); -+ } - -- if (dev_priv->swaps_pending > 0) -- drm_locked_tasklet(dev, i915_vblank_tasklet); -+ if (pipeb_stats & I915_LEGACY_BLC_EVENT_STATUS) -+ opregion_asle_intr(dev); -+ I915_WRITE(PIPEBSTAT, pipeb_stats); - } - - if (iir & I915_ASLE_INTERRUPT) - opregion_asle_intr(dev); - -- if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) -- opregion_asle_intr(dev); -+ dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); -+ -+ if (dev->pdev->msi_enabled) -+ I915_WRITE(IMR, dev_priv->irq_mask_reg); -+ I915_WRITE(IIR, iir); -+ (void) I915_READ(IIR); -+ -+ if (vblank && dev_priv->swaps_pending > 0) -+ drm_locked_tasklet(dev, i915_vblank_tasklet); - - return IRQ_HANDLED; - } -@@ -358,7 +459,7 @@ static void i915_user_irq_get(struct drm_device *dev) - spin_unlock(&dev_priv->user_irq_lock); - } - --static void i915_user_irq_put(struct drm_device *dev) -+void i915_user_irq_put(struct drm_device *dev) - { - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - -@@ -395,41 +496,10 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr) - } - - dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); -- return ret; --} -- --static int i915_driver_vblank_do_wait(struct drm_device *dev, unsigned int *sequence, -- atomic_t *counter) --{ -- drm_i915_private_t *dev_priv = dev->dev_private; -- unsigned int cur_vblank; -- int ret = 0; -- -- if (!dev_priv) { -- DRM_ERROR("called with no initialization\n"); -- return -EINVAL; -- } -- -- DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, -- (((cur_vblank = atomic_read(counter)) -- - *sequence) <= (1<<23))); -- -- *sequence = cur_vblank; - - return ret; - } - -- --int i915_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence) --{ -- return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received); --} -- --int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence) --{ -- return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received2); --} -- - /* Needs the lock as it touches the ring. - */ - int i915_irq_emit(struct drm_device *dev, void *data, -@@ -472,40 +542,88 @@ int i915_irq_wait(struct drm_device *dev, void *data, - return i915_wait_irq(dev, irqwait->irq_seq); - } - -+int i915_enable_vblank(struct drm_device *dev, int plane) -+{ -+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; -+ int pipe = i915_get_pipe(dev, plane); -+ u32 pipestat_reg = 0; -+ u32 pipestat; -+ -+ switch (pipe) { -+ case 0: -+ pipestat_reg = PIPEASTAT; -+ i915_enable_irq(dev_priv, I915_DISPLAY_PIPE_A_EVENT_INTERRUPT); -+ break; -+ case 1: -+ pipestat_reg = PIPEBSTAT; -+ i915_enable_irq(dev_priv, I915_DISPLAY_PIPE_B_EVENT_INTERRUPT); -+ break; -+ default: -+ DRM_ERROR("tried to enable vblank on non-existent pipe %d\n", -+ pipe); -+ break; -+ } -+ -+ if (pipestat_reg) { -+ pipestat = I915_READ(pipestat_reg); -+ if (IS_I965G(dev)) -+ pipestat |= PIPE_START_VBLANK_INTERRUPT_ENABLE; -+ else -+ pipestat |= PIPE_VBLANK_INTERRUPT_ENABLE; -+ /* Clear any stale interrupt status */ -+ pipestat |= (PIPE_START_VBLANK_INTERRUPT_STATUS | -+ PIPE_VBLANK_INTERRUPT_STATUS); -+ I915_WRITE(pipestat_reg, pipestat); -+ } -+ -+ return 0; -+} -+ -+void i915_disable_vblank(struct drm_device *dev, int plane) -+{ -+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; -+ int pipe = i915_get_pipe(dev, plane); -+ u32 pipestat_reg = 0; -+ u32 pipestat; -+ -+ switch (pipe) { -+ case 0: -+ pipestat_reg = PIPEASTAT; -+ i915_disable_irq(dev_priv, I915_DISPLAY_PIPE_A_EVENT_INTERRUPT); -+ break; -+ case 1: -+ pipestat_reg = PIPEBSTAT; -+ i915_disable_irq(dev_priv, I915_DISPLAY_PIPE_B_EVENT_INTERRUPT); -+ break; -+ default: -+ DRM_ERROR("tried to disable vblank on non-existent pipe %d\n", -+ pipe); -+ break; -+ } -+ -+ if (pipestat_reg) { -+ pipestat = I915_READ(pipestat_reg); -+ pipestat &= ~(PIPE_START_VBLANK_INTERRUPT_ENABLE | -+ PIPE_VBLANK_INTERRUPT_ENABLE); -+ /* Clear any stale interrupt status */ -+ pipestat |= (PIPE_START_VBLANK_INTERRUPT_STATUS | -+ PIPE_VBLANK_INTERRUPT_STATUS); -+ I915_WRITE(pipestat_reg, pipestat); -+ } -+} -+ - /* Set the vblank monitor pipe - */ - int i915_vblank_pipe_set(struct drm_device *dev, void *data, - struct drm_file *file_priv) - { - drm_i915_private_t *dev_priv = dev->dev_private; -- drm_i915_vblank_pipe_t *pipe = data; -- u32 enable_mask = 0, disable_mask = 0; - - if (!dev_priv) { - DRM_ERROR("called with no initialization\n"); - return -EINVAL; - } - -- if (pipe->pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) { -- DRM_ERROR("called with invalid pipe 0x%x\n", pipe->pipe); -- return -EINVAL; -- } -- -- if (pipe->pipe & DRM_I915_VBLANK_PIPE_A) -- enable_mask |= I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT; -- else -- disable_mask |= I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT; -- -- if (pipe->pipe & DRM_I915_VBLANK_PIPE_B) -- enable_mask |= I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; -- else -- disable_mask |= I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; -- -- i915_enable_irq(dev_priv, enable_mask); -- i915_disable_irq(dev_priv, disable_mask); -- -- dev_priv->vblank_pipe = pipe->pipe; -- - return 0; - } - -@@ -514,19 +632,13 @@ int i915_vblank_pipe_get(struct drm_device *dev, void *data, - { - drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_vblank_pipe_t *pipe = data; -- u16 flag; - - if (!dev_priv) { - DRM_ERROR("called with no initialization\n"); - return -EINVAL; - } - -- flag = I915_READ(IMR); -- pipe->pipe = 0; -- if (flag & I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT) -- pipe->pipe |= DRM_I915_VBLANK_PIPE_A; -- if (flag & I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT) -- pipe->pipe |= DRM_I915_VBLANK_PIPE_B; -+ pipe->pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; - - return 0; - } -@@ -540,9 +652,10 @@ int i915_vblank_swap(struct drm_device *dev, void *data, - drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_vblank_swap_t *swap = data; - drm_i915_vbl_swap_t *vbl_swap; -- unsigned int pipe, seqtype, curseq; -+ unsigned int pipe, seqtype, curseq, plane; - unsigned long irqflags; - struct list_head *list; -+ int ret; - - if (!dev_priv) { - DRM_ERROR("%s called with no initialization\n", __func__); -@@ -560,7 +673,8 @@ int i915_vblank_swap(struct drm_device *dev, void *data, - return -EINVAL; - } - -- pipe = (swap->seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0; -+ plane = (swap->seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0; -+ pipe = i915_get_pipe(dev, plane); - - seqtype = swap->seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE); - -@@ -579,7 +693,14 @@ int i915_vblank_swap(struct drm_device *dev, void *data, - - spin_unlock_irqrestore(&dev->drw_lock, irqflags); - -- curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received); -+ /* -+ * We take the ref here and put it when the swap actually completes -+ * in the tasklet. -+ */ -+ ret = drm_vblank_get(dev, pipe); -+ if (ret) -+ return ret; -+ curseq = drm_vblank_count(dev, pipe); - - if (seqtype == _DRM_VBLANK_RELATIVE) - swap->sequence += curseq; -@@ -589,6 +710,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data, - swap->sequence = curseq + 1; - } else { - DRM_DEBUG("Missed target sequence\n"); -+ drm_vblank_put(dev, pipe); - return -EINVAL; - } - } -@@ -599,7 +721,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data, - vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head); - - if (vbl_swap->drw_id == swap->drawable && -- vbl_swap->pipe == pipe && -+ vbl_swap->plane == plane && - vbl_swap->sequence == swap->sequence) { - spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); - DRM_DEBUG("Already scheduled\n"); -@@ -611,6 +733,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data, - - if (dev_priv->swaps_pending >= 100) { - DRM_DEBUG("Too many swaps queued\n"); -+ drm_vblank_put(dev, pipe); - return -EBUSY; - } - -@@ -618,13 +741,14 @@ int i915_vblank_swap(struct drm_device *dev, void *data, - - if (!vbl_swap) { - DRM_ERROR("Failed to allocate memory to queue swap\n"); -+ drm_vblank_put(dev, pipe); - return -ENOMEM; - } - - DRM_DEBUG("\n"); - - vbl_swap->drw_id = swap->drawable; -- vbl_swap->pipe = pipe; -+ vbl_swap->plane = plane; - vbl_swap->sequence = swap->sequence; - - spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); -@@ -643,28 +767,32 @@ void i915_driver_irq_preinstall(struct drm_device * dev) - { - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - -- I915_WRITE(HWSTAM, 0xfffe); -- I915_WRITE(IMR, 0x0); -+ I915_WRITE(HWSTAM, 0xeffe); -+ I915_WRITE(IMR, 0xffffffff); - I915_WRITE(IER, 0x0); - } - --void i915_driver_irq_postinstall(struct drm_device * dev) -+int i915_driver_irq_postinstall(struct drm_device *dev) - { - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; -+ int ret, num_pipes = 2; - - spin_lock_init(&dev_priv->swaps_lock); - INIT_LIST_HEAD(&dev_priv->vbl_swaps.head); - dev_priv->swaps_pending = 0; - -- if (!dev_priv->vblank_pipe) -- dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A; -- - /* Set initial unmasked IRQs to just the selected vblank pipes. */ - dev_priv->irq_mask_reg = ~0; -- if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A) -- dev_priv->irq_mask_reg &= ~I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT; -- if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B) -- dev_priv->irq_mask_reg &= ~I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; -+ -+ ret = drm_vblank_init(dev, num_pipes); -+ if (ret) -+ return ret; -+ -+ dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; -+ dev_priv->irq_mask_reg &= ~I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT; -+ dev_priv->irq_mask_reg &= ~I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; -+ -+ dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ - - dev_priv->irq_mask_reg &= I915_INTERRUPT_ENABLE_MASK; - -@@ -673,22 +801,29 @@ void i915_driver_irq_postinstall(struct drm_device * dev) - (void) I915_READ(IER); - - opregion_enable_asle(dev); -- - DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); -+ -+ return 0; - } - - void i915_driver_irq_uninstall(struct drm_device * dev) - { - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; -- u16 temp; -+ u32 temp; - - if (!dev_priv) - return; - -- I915_WRITE(HWSTAM, 0xffff); -- I915_WRITE(IMR, 0xffff); -+ dev_priv->vblank_pipe = 0; -+ -+ I915_WRITE(HWSTAM, 0xffffffff); -+ I915_WRITE(IMR, 0xffffffff); - I915_WRITE(IER, 0x0); - -+ temp = I915_READ(PIPEASTAT); -+ I915_WRITE(PIPEASTAT, temp); -+ temp = I915_READ(PIPEBSTAT); -+ I915_WRITE(PIPEBSTAT, temp); - temp = I915_READ(IIR); - I915_WRITE(IIR, temp); - } -diff --git a/include/drm/drm.h b/include/drm/drm.h -index 0864c69..15e5503 100644 ---- a/include/drm/drm.h -+++ b/include/drm/drm.h -@@ -454,6 +454,7 @@ struct drm_irq_busid { - enum drm_vblank_seq_type { - _DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ - _DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ -+ _DRM_VBLANK_FLIP = 0x8000000, /**< Scheduled buffer swap should flip */ - _DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */ - _DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ - _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */ -@@ -486,6 +487,19 @@ union drm_wait_vblank { - struct drm_wait_vblank_reply reply; - }; - -+#define _DRM_PRE_MODESET 1 -+#define _DRM_POST_MODESET 2 -+ -+/** -+ * DRM_IOCTL_MODESET_CTL ioctl argument type -+ * -+ * \sa drmModesetCtl(). -+ */ -+struct drm_modeset_ctl { -+ uint32_t crtc; -+ uint32_t cmd; -+}; -+ - /** - * DRM_IOCTL_AGP_ENABLE ioctl argument type. - * -@@ -570,6 +584,7 @@ struct drm_set_version { - #define DRM_IOCTL_GET_CLIENT DRM_IOWR(0x05, struct drm_client) - #define DRM_IOCTL_GET_STATS DRM_IOR( 0x06, struct drm_stats) - #define DRM_IOCTL_SET_VERSION DRM_IOWR(0x07, struct drm_set_version) -+#define DRM_IOCTL_MODESET_CTL DRM_IOW(0x08, struct drm_modeset_ctl) - - #define DRM_IOCTL_SET_UNIQUE DRM_IOW( 0x10, struct drm_unique) - #define DRM_IOCTL_AUTH_MAGIC DRM_IOW( 0x11, struct drm_auth) -diff --git a/include/drm/drmP.h b/include/drm/drmP.h -index 1c1b13e..e79ce07 100644 ---- a/include/drm/drmP.h -+++ b/include/drm/drmP.h -@@ -580,11 +580,54 @@ struct drm_driver { - int (*kernel_context_switch) (struct drm_device *dev, int old, - int new); - void (*kernel_context_switch_unlock) (struct drm_device *dev); -- int (*vblank_wait) (struct drm_device *dev, unsigned int *sequence); -- int (*vblank_wait2) (struct drm_device *dev, unsigned int *sequence); - int (*dri_library_name) (struct drm_device *dev, char *buf); - - /** -+ * get_vblank_counter - get raw hardware vblank counter -+ * @dev: DRM device -+ * @crtc: counter to fetch -+ * -+ * Driver callback for fetching a raw hardware vblank counter -+ * for @crtc. If a device doesn't have a hardware counter, the -+ * driver can simply return the value of drm_vblank_count and -+ * make the enable_vblank() and disable_vblank() hooks into no-ops, -+ * leaving interrupts enabled at all times. -+ * -+ * Wraparound handling and loss of events due to modesetting is dealt -+ * with in the DRM core code. -+ * -+ * RETURNS -+ * Raw vblank counter value. -+ */ -+ u32 (*get_vblank_counter) (struct drm_device *dev, int crtc); -+ -+ /** -+ * enable_vblank - enable vblank interrupt events -+ * @dev: DRM device -+ * @crtc: which irq to enable -+ * -+ * Enable vblank interrupts for @crtc. If the device doesn't have -+ * a hardware vblank counter, this routine should be a no-op, since -+ * interrupts will have to stay on to keep the count accurate. -+ * -+ * RETURNS -+ * Zero on success, appropriate errno if the given @crtc's vblank -+ * interrupt cannot be enabled. -+ */ -+ int (*enable_vblank) (struct drm_device *dev, int crtc); -+ -+ /** -+ * disable_vblank - disable vblank interrupt events -+ * @dev: DRM device -+ * @crtc: which irq to enable -+ * -+ * Disable vblank interrupts for @crtc. If the device doesn't have -+ * a hardware vblank counter, this routine should be a no-op, since -+ * interrupts will have to stay on to keep the count accurate. -+ */ -+ void (*disable_vblank) (struct drm_device *dev, int crtc); -+ -+ /** - * Called by \c drm_device_is_agp. Typically used to determine if a - * card is really attached to AGP or not. - * -@@ -601,7 +644,7 @@ struct drm_driver { - - irqreturn_t(*irq_handler) (DRM_IRQ_ARGS); - void (*irq_preinstall) (struct drm_device *dev); -- void (*irq_postinstall) (struct drm_device *dev); -+ int (*irq_postinstall) (struct drm_device *dev); - void (*irq_uninstall) (struct drm_device *dev); - void (*reclaim_buffers) (struct drm_device *dev, - struct drm_file * file_priv); -@@ -730,13 +773,28 @@ struct drm_device { - /** \name VBLANK IRQ support */ - /*@{ */ - -- wait_queue_head_t vbl_queue; /**< VBLANK wait queue */ -- atomic_t vbl_received; -- atomic_t vbl_received2; /**< number of secondary VBLANK interrupts */ -+ /* -+ * At load time, disabling the vblank interrupt won't be allowed since -+ * old clients may not call the modeset ioctl and therefore misbehave. -+ * Once the modeset ioctl *has* been called though, we can safely -+ * disable them when unused. -+ */ -+ int vblank_disable_allowed; -+ -+ wait_queue_head_t *vbl_queue; /**< VBLANK wait queue */ -+ atomic_t *_vblank_count; /**< number of VBLANK interrupts (driver must alloc the right number of counters) */ - spinlock_t vbl_lock; -- struct list_head vbl_sigs; /**< signal list to send on VBLANK */ -- struct list_head vbl_sigs2; /**< signals to send on secondary VBLANK */ -- unsigned int vbl_pending; -+ struct list_head *vbl_sigs; /**< signal list to send on VBLANK */ -+ atomic_t vbl_signal_pending; /* number of signals pending on all crtcs*/ -+ atomic_t *vblank_refcount; /* number of users of vblank interruptsper crtc */ -+ u32 *last_vblank; /* protected by dev->vbl_lock, used */ -+ /* for wraparound handling */ -+ int *vblank_enabled; /* so we don't call enable more than -+ once per disable */ -+ int *vblank_inmodeset; /* Display driver is setting mode */ -+ struct timer_list vblank_disable_timer; -+ -+ u32 max_vblank_count; /**< size of vblank counter register */ - spinlock_t tasklet_lock; /**< For drm_locked_tasklet */ - void (*locked_tasklet_func)(struct drm_device *dev); - -@@ -757,6 +815,7 @@ struct drm_device { - struct pci_controller *hose; - #endif - struct drm_sg_mem *sg; /**< Scatter gather memory */ -+ int num_crtcs; /**< Number of CRTCs on this device */ - void *dev_private; /**< device private data */ - struct drm_sigdata sigdata; /**< For block_all_signals */ - sigset_t sigmask; -@@ -990,10 +1049,19 @@ extern void drm_driver_irq_preinstall(struct drm_device *dev); - extern void drm_driver_irq_postinstall(struct drm_device *dev); - extern void drm_driver_irq_uninstall(struct drm_device *dev); - -+extern int drm_vblank_init(struct drm_device *dev, int num_crtcs); - extern int drm_wait_vblank(struct drm_device *dev, void *data, -- struct drm_file *file_priv); -+ struct drm_file *filp); - extern int drm_vblank_wait(struct drm_device *dev, unsigned int *vbl_seq); --extern void drm_vbl_send_signals(struct drm_device *dev); -+extern void drm_locked_tasklet(struct drm_device *dev, -+ void(*func)(struct drm_device *)); -+extern u32 drm_vblank_count(struct drm_device *dev, int crtc); -+extern void drm_handle_vblank(struct drm_device *dev, int crtc); -+extern int drm_vblank_get(struct drm_device *dev, int crtc); -+extern void drm_vblank_put(struct drm_device *dev, int crtc); -+/* Modesetting support */ -+extern int drm_modeset_ctl(struct drm_device *dev, void *data, -+ struct drm_file *file_priv); - extern void drm_locked_tasklet(struct drm_device *dev, void(*func)(struct drm_device*)); - - /* AGP/GART support (drm_agpsupport.h) */ -- cgit v1.2.3