diff options
Diffstat (limited to 'linux-core')
| -rw-r--r-- | linux-core/drmP.h | 91 | ||||
| -rw-r--r-- | linux-core/drm_drv.c | 4 | ||||
| -rw-r--r-- | linux-core/drm_irq.c | 356 | ||||
| -rw-r--r-- | linux-core/i915_drv.c | 8 | ||||
| -rw-r--r-- | linux-core/mach64_drv.c | 6 | ||||
| -rw-r--r-- | linux-core/mga_drv.c | 7 | ||||
| -rw-r--r-- | linux-core/r128_drv.c | 7 | ||||
| -rw-r--r-- | linux-core/radeon_drv.c | 8 | 
8 files changed, 392 insertions, 95 deletions
diff --git a/linux-core/drmP.h b/linux-core/drmP.h index dbf2a924..4e8b087b 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -104,10 +104,8 @@ struct drm_file;  #define DRIVER_HAVE_DMA    0x20  #define DRIVER_HAVE_IRQ    0x40  #define DRIVER_IRQ_SHARED  0x80 -#define DRIVER_IRQ_VBL     0x100 -#define DRIVER_DMA_QUEUE   0x200 -#define DRIVER_FB_DMA      0x400 -#define DRIVER_IRQ_VBL2    0x800 +#define DRIVER_DMA_QUEUE   0x100 +#define DRIVER_FB_DMA      0x200  /*@}*/ @@ -628,9 +626,51 @@ struct drm_driver {  	int (*context_dtor) (struct drm_device *dev, int context);  	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); +	void (*kernel_context_switch_unlock) (struct drm_device * dev); +	/** +	 * 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);  	int (*dri_library_name) (struct drm_device *dev, char * buf);  	/** @@ -649,7 +689,7 @@ struct drm_driver {  /* these have to be filled in */  	 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); @@ -787,13 +827,19 @@ 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 */ +	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 interrupts per crtc */ +	u32 *last_vblank;		/* protected by dev->vbl_lock, used */ +					/* for wraparound handling */ +	u32 *vblank_offset;		/* used to track how many vblanks */ +	u32 *vblank_premodeset;		/*  were lost during modeset */ +	struct timer_list vblank_disable_timer; + +	unsigned long max_vblank_count; /**< size of vblank counter register */  	spinlock_t tasklet_lock;	/**< For drm_locked_tasklet */  	void (*locked_tasklet_func)(struct drm_device *dev); @@ -813,6 +859,7 @@ struct drm_device {  #ifdef __alpha__  	struct pci_controller *hose;  #endif +	int num_crtcs;			/**< Number of CRTCs on this device */  	struct drm_sg_mem *sg;		/**< Scatter gather memory */  	void *dev_private;		/**< device private data */  	struct drm_sigdata sigdata;		/**< For block_all_signals */ @@ -1084,11 +1131,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_wait_vblank(struct drm_device *dev, void *data, -			   struct drm_file *file_priv); -extern int drm_vblank_wait(struct drm_device *dev, unsigned int *vbl_seq); -extern void drm_vbl_send_signals(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 *filp); +extern int drm_vblank_wait(struct drm_device * dev, unsigned int *vbl_seq);  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_update_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);  				/* AGP/GART support (drm_agpsupport.h) */  extern struct drm_agp_head *drm_agp_init(struct drm_device *dev); diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 343d5f32..3c2794d0 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -115,14 +115,12 @@ static struct drm_ioctl_desc drm_ioctls[] = {  	DRM_IOCTL_DEF(DRM_IOCTL_SG_ALLOC, drm_sg_alloc_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),  	DRM_IOCTL_DEF(DRM_IOCTL_SG_FREE, drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), -  	DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank, 0), -	//	DRM_IOCTL_DEF(DRM_IOCTL_BUFOBJ, drm_bo_ioctl, DRM_AUTH), +	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), -  	DRM_IOCTL_DEF(DRM_IOCTL_MM_INIT, drm_mm_init_ioctl,  		      DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),  	DRM_IOCTL_DEF(DRM_IOCTL_MM_TAKEDOWN, drm_mm_takedown_ioctl, diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index 866878aa..2a5a4539 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -71,18 +71,100 @@ 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; +	int i; + +	for (i = 0; i < dev->num_crtcs; i++) +		if (atomic_read(&dev->vblank_refcount[i]) == 0) +			dev->driver->disable_vblank(dev, i); +} + +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->last_vblank = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER); +	if (!dev->last_vblank) +		goto err; + +	dev->vblank_premodeset = drm_calloc(num_crtcs, sizeof(u32), +					    DRM_MEM_DRIVER); +	if (!dev->vblank_premodeset) +		goto err; + +	dev->vblank_offset = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER); +	if (!dev->vblank_offset) +		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); +	} + +	return 0; + +err: +	drm_free(dev->vbl_queue, sizeof(*dev->vbl_queue) * num_crtcs, +		 DRM_MEM_DRIVER); +	drm_free(dev->vbl_sigs, sizeof(*dev->vbl_sigs) * num_crtcs, +		 DRM_MEM_DRIVER); +	drm_free(dev->_vblank_count, sizeof(*dev->_vblank_count) * num_crtcs, +		 DRM_MEM_DRIVER); +	drm_free(dev->vblank_refcount, sizeof(*dev->vblank_refcount) * +		 num_crtcs, DRM_MEM_DRIVER); +	drm_free(dev->last_vblank, sizeof(*dev->last_vblank) * num_crtcs, +		 DRM_MEM_DRIVER); +	drm_free(dev->vblank_premodeset, sizeof(*dev->vblank_premodeset) * +		 num_crtcs, DRM_MEM_DRIVER); +	drm_free(dev->vblank_offset, sizeof(*dev->vblank_offset) * num_crtcs, +		 DRM_MEM_DRIVER); +	return ret; +} +EXPORT_SYMBOL(drm_vblank_init); +  /**   * Install IRQ handler.   *   * \param dev DRM device.   * - * 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.   */  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)) @@ -108,17 +190,6 @@ int drm_irq_install(struct drm_device * dev)  	DRM_DEBUG("irq=%d\n", dev->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); @@ -136,9 +207,14 @@ 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); @@ -213,6 +289,149 @@ 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]) + +		dev->vblank_offset[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. + */ +void drm_update_vblank_count(struct drm_device *dev, int crtc) +{ +	unsigned long irqflags; +	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); +	spin_lock_irqsave(&dev->vbl_lock, irqflags); +	if (cur_vblank < dev->last_vblank[crtc]) { +		diff = dev->max_vblank_count - +			dev->last_vblank[crtc]; +		diff += cur_vblank; +	} else { +		diff = cur_vblank - dev->last_vblank[crtc]; +	} +	dev->last_vblank[crtc] = cur_vblank; +	spin_unlock_irqrestore(&dev->vbl_lock, irqflags); + +	atomic_add(diff, &dev->_vblank_count[crtc]); +} +EXPORT_SYMBOL(drm_update_vblank_count); + +/** + * 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.  Note callers will probably want to update the master counter + * using drm_update_vblank_count() above before calling this routine so that + * wakeups occur on the right vblank event. + * + * RETURNS + * Zero on success, nonzero on failure. + */ +int drm_vblank_get(struct drm_device *dev, int crtc) +{ +	int ret = 0; + +	/* Going from 0->1 means we have to enable interrupts again */ +	if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1) { +		ret = dev->driver->enable_vblank(dev, crtc); +		if (ret) +			atomic_dec(&dev->vblank_refcount[crtc]); +	} + +	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, +			  round_jiffies_relative(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. + */ +int drm_modeset_ctl(struct drm_device *dev, void *data, +		    struct drm_file *file_priv) +{ +	drm_modeset_ctl_t __user *argp = (void __user *)data; +	drm_modeset_ctl_t modeset; +	int crtc, ret = 0; +	u32 new; + +	if (copy_from_user(&modeset, argp, sizeof(modeset))) { +		ret = -EFAULT; +		goto out; +	} + +	crtc = modeset.arg; +	if (crtc >= dev->num_crtcs) { +		ret = -EINVAL; +		goto out; +	} + +	switch (modeset.cmd) { +	case _DRM_PRE_MODESET: +		dev->vblank_premodeset[crtc] = +			dev->driver->get_vblank_counter(dev, crtc); +		break; +	case _DRM_POST_MODESET: +		new = dev->driver->get_vblank_counter(dev, crtc); +		dev->vblank_offset[crtc] = dev->vblank_premodeset[crtc] - new; +		break; +	default: +		ret = -EINVAL; +		break; +	} + +out: +	return ret; +} + +/**   * Wait for VBLANK.   *   * \param inode device inode. @@ -231,12 +450,13 @@ 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->irq) || (!dev->irq_enabled))  		return -EINVAL; @@ -250,13 +470,13 @@ 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); +	drm_update_vblank_count(dev, crtc); +	seq = drm_vblank_count(dev, crtc);  	switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) {  	case _DRM_VBLANK_RELATIVE: @@ -275,8 +495,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); @@ -297,22 +516,26 @@ 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;  		} -		dev->vbl_pending++; -  		spin_unlock_irqrestore(&dev->vbl_lock, irqflags); -		if (! -		    (vbl_sig = -		     drm_alloc(sizeof(struct drm_vbl_sig), DRM_MEM_DRIVER))) { +		vbl_sig = drm_calloc(1, sizeof(struct drm_vbl_sig), +				     DRM_MEM_DRIVER); +		if (!vbl_sig)  			return -ENOMEM; + +		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; @@ -326,17 +549,20 @@ 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); - +		unsigned long cur_vblank; + +		ret = drm_vblank_get(dev, crtc); +		if (ret) +			return ret; +		DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ, +			    (((cur_vblank = drm_vblank_count(dev, crtc)) +			      - vblwait->request.sequence) <= (1 << 23))); +		drm_vblank_put(dev, crtc);  		do_gettimeofday(&now); +  		vblwait->reply.tval_sec = now.tv_sec;  		vblwait->reply.tval_usec = now.tv_usec; +		vblwait->reply.sequence = cur_vblank;  	}        done: @@ -347,43 +573,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); - -		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); +	vbl_sigs = &dev->vbl_sigs[crtc]; +	vbl_seq = drm_vblank_count(dev, crtc); -				list_del(&vbl_sig->head); +	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); -				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) +{ +	drm_update_vblank_count(dev, crtc); +	DRM_WAKEUP(&dev->vbl_queue[crtc]); +	drm_vbl_send_signals(dev, crtc); +} +EXPORT_SYMBOL(drm_handle_vblank);  /**   * Tasklet wrapper function. diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index a8ce0f5e..a5f60ee1 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -536,8 +536,7 @@ static struct drm_driver driver = {  	 */  	.driver_features =  	    DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | /* DRIVER_USE_MTRR | */ -	    DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL | -	    DRIVER_IRQ_VBL2, +	    DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,  	.load = i915_driver_load,  	.unload = i915_driver_unload,  	.firstopen = i915_driver_firstopen, @@ -546,8 +545,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/linux-core/mach64_drv.c b/linux-core/mach64_drv.c index 9709934d..16bc9ff3 100644 --- a/linux-core/mach64_drv.c +++ b/linux-core/mach64_drv.c @@ -42,9 +42,11 @@ static int probe(struct pci_dev *pdev, const struct pci_device_id *ent);  static struct drm_driver driver = {  	.driver_features =  	    DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_HAVE_DMA -	    | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL, +	    | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,  	.lastclose = mach64_driver_lastclose, -	.vblank_wait = mach64_driver_vblank_wait, +	.get_vblank_counter = mach64_get_vblank_counter, +	.enable_vblank = mach64_enable_vblank, +	.disable_vblank = mach64_disable_vblank,  	.irq_preinstall = mach64_driver_irq_preinstall,  	.irq_postinstall = mach64_driver_irq_postinstall,  	.irq_uninstall = mach64_driver_irq_uninstall, diff --git a/linux-core/mga_drv.c b/linux-core/mga_drv.c index bab90aa5..14a0be45 100644 --- a/linux-core/mga_drv.c +++ b/linux-core/mga_drv.c @@ -46,15 +46,16 @@ static int probe(struct pci_dev *pdev, const struct pci_device_id *ent);  static struct drm_driver driver = {  	.driver_features =  	    DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | -	    DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | -	    DRIVER_IRQ_VBL, +	    DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,  	.dev_priv_size = sizeof (drm_mga_buf_priv_t),  	.load = mga_driver_load,  	.unload = mga_driver_unload,  	.lastclose = mga_driver_lastclose,  	.dma_quiescent = mga_driver_dma_quiescent,  	.device_is_agp = mga_driver_device_is_agp, -	.vblank_wait = mga_driver_vblank_wait, +	.get_vblank_counter = mga_get_vblank_counter, +	.enable_vblank = mga_enable_vblank, +	.disable_vblank = mga_disable_vblank,  	.irq_preinstall = mga_driver_irq_preinstall,  	.irq_postinstall = mga_driver_irq_postinstall,  	.irq_uninstall = mga_driver_irq_uninstall, diff --git a/linux-core/r128_drv.c b/linux-core/r128_drv.c index ef4a5cbd..7b6159b9 100644 --- a/linux-core/r128_drv.c +++ b/linux-core/r128_drv.c @@ -44,12 +44,13 @@ static int probe(struct pci_dev *pdev, const struct pci_device_id *ent);  static struct drm_driver driver = {  	.driver_features =  	    DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG | -	    DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | -	    DRIVER_IRQ_VBL, +	    DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,  	.dev_priv_size = sizeof(drm_r128_buf_priv_t),  	.preclose = r128_driver_preclose,  	.lastclose = r128_driver_lastclose, -	.vblank_wait = r128_driver_vblank_wait, +	.get_vblank_counter = r128_get_vblank_counter, +	.enable_vblank = r128_enable_vblank, +	.disable_vblank = r128_disable_vblank,  	.irq_preinstall = r128_driver_irq_preinstall,  	.irq_postinstall = r128_driver_irq_postinstall,  	.irq_uninstall = r128_driver_irq_uninstall, diff --git a/linux-core/radeon_drv.c b/linux-core/radeon_drv.c index d847f3cd..f0f3320e 100644 --- a/linux-core/radeon_drv.c +++ b/linux-core/radeon_drv.c @@ -60,8 +60,7 @@ static int probe(struct pci_dev *pdev, const struct pci_device_id *ent);  static struct drm_driver driver = {  	.driver_features =  	    DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG | -	    DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED | -	    DRIVER_IRQ_VBL | DRIVER_IRQ_VBL2, +	    DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED,  	.dev_priv_size = sizeof(drm_radeon_buf_priv_t),  	.load = radeon_driver_load,  	.firstopen = radeon_driver_firstopen, @@ -70,8 +69,9 @@ static struct drm_driver driver = {  	.postclose = radeon_driver_postclose,  	.lastclose = radeon_driver_lastclose,  	.unload = radeon_driver_unload, -	.vblank_wait = radeon_driver_vblank_wait, -	.vblank_wait2 = radeon_driver_vblank_wait2, +	.get_vblank_counter = radeon_get_vblank_counter, +	.enable_vblank = radeon_enable_vblank, +	.disable_vblank = radeon_disable_vblank,  	.dri_library_name = dri_library_name,  	.irq_preinstall = radeon_driver_irq_preinstall,  	.irq_postinstall = radeon_driver_irq_postinstall,  | 
