Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5380e929 authored by Ville Syrjälä's avatar Ville Syrjälä Committed by Dave Airlie
Browse files

drm: Collect per-crtc vblank stuff to a struct



drm_vblank_init() is too ugly. Make it a bit easier on the eye by
collecting all the per-crtc vblank counters, timestamps etc. to
a structure and just allocate an array of those.

Signed-off-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Reviewed-by: default avatarAlex Deucher <alexander.deucher@amd.com>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent bf507d90
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -163,13 +163,13 @@ int drm_vblank_info(struct seq_file *m, void *data)
	mutex_lock(&dev->struct_mutex);
	for (crtc = 0; crtc < dev->num_crtcs; crtc++) {
		seq_printf(m, "CRTC %d enable:     %d\n",
			   crtc, atomic_read(&dev->vblank_refcount[crtc]));
			   crtc, atomic_read(&dev->vblank[crtc].refcount));
		seq_printf(m, "CRTC %d counter:    %d\n",
			   crtc, drm_vblank_count(dev, crtc));
		seq_printf(m, "CRTC %d last wait:  %d\n",
			   crtc, dev->last_vblank_wait[crtc]);
			   crtc, dev->vblank[crtc].last_wait);
		seq_printf(m, "CRTC %d in modeset: %d\n",
			   crtc, dev->vblank_inmodeset[crtc]);
			   crtc, dev->vblank[crtc].inmodeset);
	}
	mutex_unlock(&dev->struct_mutex);
	return 0;
+47 −91
Original line number Diff line number Diff line
@@ -43,9 +43,8 @@
#include <linux/export.h>

/* Access macro for slots in vblank timestamp ringbuffer. */
#define vblanktimestamp(dev, crtc, count) ( \
	(dev)->_vblank_time[(crtc) * DRM_VBLANKTIME_RBSIZE + \
	((count) % DRM_VBLANKTIME_RBSIZE)])
#define vblanktimestamp(dev, crtc, count) \
	((dev)->vblank[crtc].time[(count) % DRM_VBLANKTIME_RBSIZE])

/* Retry timestamp calculation up to 3 times to satisfy
 * drm_timestamp_precision before giving up.
@@ -89,8 +88,7 @@ int drm_irq_by_busid(struct drm_device *dev, void *data,
 */
static void clear_vblank_timestamps(struct drm_device *dev, int crtc)
{
	memset(&dev->_vblank_time[crtc * DRM_VBLANKTIME_RBSIZE], 0,
		DRM_VBLANKTIME_RBSIZE * sizeof(struct timeval));
	memset(dev->vblank[crtc].time, 0, sizeof(dev->vblank[crtc].time));
}

/*
@@ -115,7 +113,7 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc)
	spin_lock_irqsave(&dev->vblank_time_lock, irqflags);

	dev->driver->disable_vblank(dev, crtc);
	dev->vblank_enabled[crtc] = false;
	dev->vblank[crtc].enabled = false;

	/* No further vblank irq's will be processed after
	 * this point. Get current hardware vblank count and
@@ -130,9 +128,9 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc)
	 * delayed gpu counter increment.
	 */
	do {
		dev->last_vblank[crtc] = dev->driver->get_vblank_counter(dev, crtc);
		dev->vblank[crtc].last = dev->driver->get_vblank_counter(dev, crtc);
		vblrc = drm_get_last_vbltimestamp(dev, crtc, &tvblank, 0);
	} while (dev->last_vblank[crtc] != dev->driver->get_vblank_counter(dev, crtc) && (--count) && vblrc);
	} while (dev->vblank[crtc].last != dev->driver->get_vblank_counter(dev, crtc) && (--count) && vblrc);

	if (!count)
		vblrc = 0;
@@ -140,7 +138,7 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc)
	/* Compute time difference to stored timestamp of last vblank
	 * as updated by last invocation of drm_handle_vblank() in vblank irq.
	 */
	vblcount = atomic_read(&dev->_vblank_count[crtc]);
	vblcount = atomic_read(&dev->vblank[crtc].count);
	diff_ns = timeval_to_ns(&tvblank) -
		  timeval_to_ns(&vblanktimestamp(dev, crtc, vblcount));

@@ -157,7 +155,7 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc)
	 * hope for the best.
	 */
	if ((vblrc > 0) && (abs64(diff_ns) > 1000000)) {
		atomic_inc(&dev->_vblank_count[crtc]);
		atomic_inc(&dev->vblank[crtc].count);
		smp_mb__after_atomic_inc();
	}

@@ -178,8 +176,8 @@ static void vblank_disable_fn(unsigned long arg)

	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]) {
		if (atomic_read(&dev->vblank[i].refcount) == 0 &&
		    dev->vblank[i].enabled) {
			DRM_DEBUG("disabling vblank on crtc %d\n", i);
			vblank_disable_and_save(dev, i);
		}
@@ -197,14 +195,7 @@ void drm_vblank_cleanup(struct drm_device *dev)

	vblank_disable_fn((unsigned long)dev);

	kfree(dev->vbl_queue);
	kfree(dev->_vblank_count);
	kfree(dev->vblank_refcount);
	kfree(dev->vblank_enabled);
	kfree(dev->last_vblank);
	kfree(dev->last_vblank_wait);
	kfree(dev->vblank_inmodeset);
	kfree(dev->_vblank_time);
	kfree(dev->vblank);

	dev->num_crtcs = 0;
}
@@ -221,40 +212,12 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs)

	dev->num_crtcs = num_crtcs;

	dev->vbl_queue = kmalloc(sizeof(wait_queue_head_t) * num_crtcs,
				 GFP_KERNEL);
	if (!dev->vbl_queue)
	dev->vblank = kcalloc(num_crtcs, sizeof(*dev->vblank), GFP_KERNEL);
	if (!dev->vblank)
		goto err;

	dev->_vblank_count = kmalloc(sizeof(atomic_t) * num_crtcs, GFP_KERNEL);
	if (!dev->_vblank_count)
		goto err;

	dev->vblank_refcount = kmalloc(sizeof(atomic_t) * num_crtcs,
				       GFP_KERNEL);
	if (!dev->vblank_refcount)
		goto err;

	dev->vblank_enabled = kcalloc(num_crtcs, sizeof(bool), GFP_KERNEL);
	if (!dev->vblank_enabled)
		goto err;

	dev->last_vblank = kcalloc(num_crtcs, sizeof(u32), GFP_KERNEL);
	if (!dev->last_vblank)
		goto err;

	dev->last_vblank_wait = kcalloc(num_crtcs, sizeof(u32), GFP_KERNEL);
	if (!dev->last_vblank_wait)
		goto err;

	dev->vblank_inmodeset = kcalloc(num_crtcs, sizeof(int), GFP_KERNEL);
	if (!dev->vblank_inmodeset)
		goto err;

	dev->_vblank_time = kcalloc(num_crtcs * DRM_VBLANKTIME_RBSIZE,
				    sizeof(struct timeval), GFP_KERNEL);
	if (!dev->_vblank_time)
		goto err;
	for (i = 0; i < num_crtcs; i++)
		init_waitqueue_head(&dev->vblank[i].queue);

	DRM_INFO("Supports vblank timestamp caching Rev 1 (10.10.2010).\n");

@@ -264,13 +227,6 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs)
	else
		DRM_INFO("No driver support for vblank timestamp query.\n");

	/* Zero per-crtc vblank stuff */
	for (i = 0; i < num_crtcs; i++) {
		init_waitqueue_head(&dev->vbl_queue[i]);
		atomic_set(&dev->_vblank_count[i], 0);
		atomic_set(&dev->vblank_refcount[i], 0);
	}

	dev->vblank_disable_allowed = false;

	return 0;
@@ -411,9 +367,9 @@ int drm_irq_uninstall(struct drm_device *dev)
	if (dev->num_crtcs) {
		spin_lock_irqsave(&dev->vbl_lock, irqflags);
		for (i = 0; i < dev->num_crtcs; i++) {
			DRM_WAKEUP(&dev->vbl_queue[i]);
			dev->vblank_enabled[i] = false;
			dev->last_vblank[i] =
			DRM_WAKEUP(&dev->vblank[i].queue);
			dev->vblank[i].enabled = false;
			dev->vblank[i].last =
				dev->driver->get_vblank_counter(dev, i);
		}
		spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
@@ -796,7 +752,7 @@ EXPORT_SYMBOL(drm_get_last_vbltimestamp);
 */
u32 drm_vblank_count(struct drm_device *dev, int crtc)
{
	return atomic_read(&dev->_vblank_count[crtc]);
	return atomic_read(&dev->vblank[crtc].count);
}
EXPORT_SYMBOL(drm_vblank_count);

@@ -825,10 +781,10 @@ u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc,
	 * a seqlock.
	 */
	do {
		cur_vblank = atomic_read(&dev->_vblank_count[crtc]);
		cur_vblank = atomic_read(&dev->vblank[crtc].count);
		*vblanktime = vblanktimestamp(dev, crtc, cur_vblank);
		smp_rmb();
	} while (cur_vblank != atomic_read(&dev->_vblank_count[crtc]));
	} while (cur_vblank != atomic_read(&dev->vblank[crtc].count));

	return cur_vblank;
}
@@ -915,12 +871,12 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc)
	} while (cur_vblank != dev->driver->get_vblank_counter(dev, crtc));

	/* Deal with counter wrap */
	diff = cur_vblank - dev->last_vblank[crtc];
	if (cur_vblank < dev->last_vblank[crtc]) {
	diff = cur_vblank - dev->vblank[crtc].last;
	if (cur_vblank < dev->vblank[crtc].last) {
		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);
			  crtc, dev->vblank[crtc].last, cur_vblank, diff);
	}

	DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n",
@@ -931,12 +887,12 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc)
	 * reinitialize delayed at next vblank interrupt in that case.
	 */
	if (rc) {
		tslot = atomic_read(&dev->_vblank_count[crtc]) + diff;
		tslot = atomic_read(&dev->vblank[crtc].count) + diff;
		vblanktimestamp(dev, crtc, tslot) = t_vblank;
	}

	smp_mb__before_atomic_inc();
	atomic_add(diff, &dev->_vblank_count[crtc]);
	atomic_add(diff, &dev->vblank[crtc].count);
	smp_mb__after_atomic_inc();
}

@@ -958,9 +914,9 @@ int drm_vblank_get(struct drm_device *dev, int crtc)

	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) {
	if (atomic_add_return(1, &dev->vblank[crtc].refcount) == 1) {
		spin_lock_irqsave(&dev->vblank_time_lock, irqflags2);
		if (!dev->vblank_enabled[crtc]) {
		if (!dev->vblank[crtc].enabled) {
			/* Enable vblank irqs under vblank_time_lock protection.
			 * All vblank count & timestamp updates are held off
			 * until we are done reinitializing master counter and
@@ -971,16 +927,16 @@ int drm_vblank_get(struct drm_device *dev, int crtc)
			DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n",
				  crtc, ret);
			if (ret)
				atomic_dec(&dev->vblank_refcount[crtc]);
				atomic_dec(&dev->vblank[crtc].refcount);
			else {
				dev->vblank_enabled[crtc] = true;
				dev->vblank[crtc].enabled = true;
				drm_update_vblank_count(dev, crtc);
			}
		}
		spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags2);
	} else {
		if (!dev->vblank_enabled[crtc]) {
			atomic_dec(&dev->vblank_refcount[crtc]);
		if (!dev->vblank[crtc].enabled) {
			atomic_dec(&dev->vblank[crtc].refcount);
			ret = -EINVAL;
		}
	}
@@ -1000,10 +956,10 @@ EXPORT_SYMBOL(drm_vblank_get);
 */
void drm_vblank_put(struct drm_device *dev, int crtc)
{
	BUG_ON(atomic_read(&dev->vblank_refcount[crtc]) == 0);
	BUG_ON(atomic_read(&dev->vblank[crtc].refcount) == 0);

	/* Last user schedules interrupt disable */
	if (atomic_dec_and_test(&dev->vblank_refcount[crtc]) &&
	if (atomic_dec_and_test(&dev->vblank[crtc].refcount) &&
	    (drm_vblank_offdelay > 0))
		mod_timer(&dev->vblank_disable_timer,
			  jiffies + ((drm_vblank_offdelay * DRM_HZ)/1000));
@@ -1026,7 +982,7 @@ void drm_vblank_off(struct drm_device *dev, int crtc)

	spin_lock_irqsave(&dev->vbl_lock, irqflags);
	vblank_disable_and_save(dev, crtc);
	DRM_WAKEUP(&dev->vbl_queue[crtc]);
	DRM_WAKEUP(&dev->vblank[crtc].queue);

	/* Send any queued vblank events, lest the natives grow disquiet */
	seq = drm_vblank_count_and_time(dev, crtc, &now);
@@ -1068,10 +1024,10 @@ void drm_vblank_pre_modeset(struct drm_device *dev, int crtc)
	 * to avoid corrupting the count if multiple, mismatch calls occur),
	 * so that interrupts remain enabled in the interim.
	 */
	if (!dev->vblank_inmodeset[crtc]) {
		dev->vblank_inmodeset[crtc] = 0x1;
	if (!dev->vblank[crtc].inmodeset) {
		dev->vblank[crtc].inmodeset = 0x1;
		if (drm_vblank_get(dev, crtc) == 0)
			dev->vblank_inmodeset[crtc] |= 0x2;
			dev->vblank[crtc].inmodeset |= 0x2;
	}
}
EXPORT_SYMBOL(drm_vblank_pre_modeset);
@@ -1084,15 +1040,15 @@ void drm_vblank_post_modeset(struct drm_device *dev, int crtc)
	if (!dev->num_crtcs)
		return;

	if (dev->vblank_inmodeset[crtc]) {
	if (dev->vblank[crtc].inmodeset) {
		spin_lock_irqsave(&dev->vbl_lock, irqflags);
		dev->vblank_disable_allowed = true;
		spin_unlock_irqrestore(&dev->vbl_lock, irqflags);

		if (dev->vblank_inmodeset[crtc] & 0x2)
		if (dev->vblank[crtc].inmodeset & 0x2)
			drm_vblank_put(dev, crtc);

		dev->vblank_inmodeset[crtc] = 0;
		dev->vblank[crtc].inmodeset = 0;
	}
}
EXPORT_SYMBOL(drm_vblank_post_modeset);
@@ -1289,8 +1245,8 @@ int drm_wait_vblank(struct drm_device *dev, void *data,

	DRM_DEBUG("waiting on vblank count %d, crtc %d\n",
		  vblwait->request.sequence, crtc);
	dev->last_vblank_wait[crtc] = vblwait->request.sequence;
	DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ,
	dev->vblank[crtc].last_wait = vblwait->request.sequence;
	DRM_WAIT_ON(ret, dev->vblank[crtc].queue, 3 * DRM_HZ,
		    (((drm_vblank_count(dev, crtc) -
		       vblwait->request.sequence) <= (1 << 23)) ||
		     !dev->irq_enabled));
@@ -1368,7 +1324,7 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc)
	spin_lock_irqsave(&dev->vblank_time_lock, irqflags);

	/* Vblank irq handling disabled. Nothing to do. */
	if (!dev->vblank_enabled[crtc]) {
	if (!dev->vblank[crtc].enabled) {
		spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags);
		return false;
	}
@@ -1378,7 +1334,7 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc)
	 */

	/* Get current timestamp and count. */
	vblcount = atomic_read(&dev->_vblank_count[crtc]);
	vblcount = atomic_read(&dev->vblank[crtc].count);
	drm_get_last_vbltimestamp(dev, crtc, &tvblank, DRM_CALLED_FROM_VBLIRQ);

	/* Compute time difference to timestamp of last vblank */
@@ -1402,14 +1358,14 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc)
		 * the timestamp computed above.
		 */
		smp_mb__before_atomic_inc();
		atomic_inc(&dev->_vblank_count[crtc]);
		atomic_inc(&dev->vblank[crtc].count);
		smp_mb__after_atomic_inc();
	} else {
		DRM_DEBUG("crtc %d: Redundant vblirq ignored. diff_ns = %d\n",
			  crtc, (int) diff_ns);
	}

	DRM_WAKEUP(&dev->vbl_queue[crtc]);
	DRM_WAKEUP(&dev->vblank[crtc].queue);
	drm_handle_vblank_events(dev, crtc);

	spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags);
+11 −11
Original line number Diff line number Diff line
@@ -271,15 +271,15 @@ void psb_irq_preinstall(struct drm_device *dev)

	if (gma_power_is_on(dev))
		PSB_WVDC32(0xFFFFFFFF, PSB_HWSTAM);
	if (dev->vblank_enabled[0])
	if (dev->vblank[0].enabled)
		dev_priv->vdc_irq_mask |= _PSB_VSYNC_PIPEA_FLAG;
	if (dev->vblank_enabled[1])
	if (dev->vblank[1].enabled)
		dev_priv->vdc_irq_mask |= _PSB_VSYNC_PIPEB_FLAG;

	/* FIXME: Handle Medfield irq mask
	if (dev->vblank_enabled[1])
	if (dev->vblank[1].enabled)
		dev_priv->vdc_irq_mask |= _MDFLD_PIPEB_EVENT_FLAG;
	if (dev->vblank_enabled[2])
	if (dev->vblank[2].enabled)
		dev_priv->vdc_irq_mask |= _MDFLD_PIPEC_EVENT_FLAG;
	*/

@@ -305,17 +305,17 @@ int psb_irq_postinstall(struct drm_device *dev)
	PSB_WVDC32(dev_priv->vdc_irq_mask, PSB_INT_ENABLE_R);
	PSB_WVDC32(0xFFFFFFFF, PSB_HWSTAM);

	if (dev->vblank_enabled[0])
	if (dev->vblank[0].enabled)
		psb_enable_pipestat(dev_priv, 0, PIPE_VBLANK_INTERRUPT_ENABLE);
	else
		psb_disable_pipestat(dev_priv, 0, PIPE_VBLANK_INTERRUPT_ENABLE);

	if (dev->vblank_enabled[1])
	if (dev->vblank[1].enabled)
		psb_enable_pipestat(dev_priv, 1, PIPE_VBLANK_INTERRUPT_ENABLE);
	else
		psb_disable_pipestat(dev_priv, 1, PIPE_VBLANK_INTERRUPT_ENABLE);

	if (dev->vblank_enabled[2])
	if (dev->vblank[2].enabled)
		psb_enable_pipestat(dev_priv, 2, PIPE_VBLANK_INTERRUPT_ENABLE);
	else
		psb_disable_pipestat(dev_priv, 2, PIPE_VBLANK_INTERRUPT_ENABLE);
@@ -339,13 +339,13 @@ void psb_irq_uninstall(struct drm_device *dev)

	PSB_WVDC32(0xFFFFFFFF, PSB_HWSTAM);

	if (dev->vblank_enabled[0])
	if (dev->vblank[0].enabled)
		psb_disable_pipestat(dev_priv, 0, PIPE_VBLANK_INTERRUPT_ENABLE);

	if (dev->vblank_enabled[1])
	if (dev->vblank[1].enabled)
		psb_disable_pipestat(dev_priv, 1, PIPE_VBLANK_INTERRUPT_ENABLE);

	if (dev->vblank_enabled[2])
	if (dev->vblank[2].enabled)
		psb_disable_pipestat(dev_priv, 2, PIPE_VBLANK_INTERRUPT_ENABLE);

	dev_priv->vdc_irq_mask &= _PSB_IRQ_SGX_FLAG |
@@ -456,7 +456,7 @@ static int psb_vblank_do_wait(struct drm_device *dev,
{
	unsigned int cur_vblank;
	int ret = 0;
	DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
	DRM_WAIT_ON(ret, dev->vblank.queue, 3 * DRM_HZ,
		    (((cur_vblank = atomic_read(counter))
		      - *sequence) <= (1 << 23)));
	*sequence = cur_vblank;
+1 −1
Original line number Diff line number Diff line
@@ -5340,7 +5340,7 @@ static void __intel_set_power_well(struct drm_device *dev, bool enable)
			spin_lock_irqsave(&dev->vbl_lock, irqflags);
			for_each_pipe(p)
				if (p != PIPE_A)
					dev->last_vblank[p] = 0;
					dev->vblank[p].last = 0;
			spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
		}
	}
+3 −3
Original line number Diff line number Diff line
@@ -307,9 +307,9 @@ int omap_drm_irq_uninstall(struct drm_device *dev)
	if (dev->num_crtcs) {
		spin_lock_irqsave(&dev->vbl_lock, irqflags);
		for (i = 0; i < dev->num_crtcs; i++) {
			DRM_WAKEUP(&dev->vbl_queue[i]);
			dev->vblank_enabled[i] = false;
			dev->last_vblank[i] =
			DRM_WAKEUP(&dev->vblank[i].queue);
			dev->vblank[i].enabled = false;
			dev->vblank[i].last =
				dev->driver->get_vblank_counter(dev, i);
		}
		spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
Loading