aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/drm_irq.c43
1 files changed, 43 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index 685b0ebe5fb2..0ac2608ba150 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -224,6 +224,49 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
224 diff = (flags & DRM_CALLED_FROM_VBLIRQ) != 0; 224 diff = (flags & DRM_CALLED_FROM_VBLIRQ) != 0;
225 } 225 }
226 226
227 /*
228 * FIMXE: Need to replace this hack with proper seqlocks.
229 *
230 * Restrict the bump of the software vblank counter to a safe maximum
231 * value of +1 whenever there is the possibility that concurrent readers
232 * of vblank timestamps could be active at the moment, as the current
233 * implementation of the timestamp caching and updating is not safe
234 * against concurrent readers for calls to store_vblank() with a bump
235 * of anything but +1. A bump != 1 would very likely return corrupted
236 * timestamps to userspace, because the same slot in the cache could
237 * be concurrently written by store_vblank() and read by one of those
238 * readers without the read-retry logic detecting the collision.
239 *
240 * Concurrent readers can exist when we are called from the
241 * drm_vblank_off() or drm_vblank_on() functions and other non-vblank-
242 * irq callers. However, all those calls to us are happening with the
243 * vbl_lock locked to prevent drm_vblank_get(), so the vblank refcount
244 * can't increase while we are executing. Therefore a zero refcount at
245 * this point is safe for arbitrary counter bumps if we are called
246 * outside vblank irq, a non-zero count is not 100% safe. Unfortunately
247 * we must also accept a refcount of 1, as whenever we are called from
248 * drm_vblank_get() -> drm_vblank_enable() the refcount will be 1 and
249 * we must let that one pass through in order to not lose vblank counts
250 * during vblank irq off - which would completely defeat the whole
251 * point of this routine.
252 *
253 * Whenever we are called from vblank irq, we have to assume concurrent
254 * readers exist or can show up any time during our execution, even if
255 * the refcount is currently zero, as vblank irqs are usually only
256 * enabled due to the presence of readers, and because when we are called
257 * from vblank irq we can't hold the vbl_lock to protect us from sudden
258 * bumps in vblank refcount. Therefore also restrict bumps to +1 when
259 * called from vblank irq.
260 */
261 if ((diff > 1) && (atomic_read(&vblank->refcount) > 1 ||
262 (flags & DRM_CALLED_FROM_VBLIRQ))) {
263 DRM_DEBUG_VBL("clamping vblank bump to 1 on crtc %u: diffr=%u "
264 "refcount %u, vblirq %u\n", pipe, diff,
265 atomic_read(&vblank->refcount),
266 (flags & DRM_CALLED_FROM_VBLIRQ) != 0);
267 diff = 1;
268 }
269
227 DRM_DEBUG_VBL("updating vblank count on crtc %u:" 270 DRM_DEBUG_VBL("updating vblank count on crtc %u:"
228 " current=%u, diff=%u, hw=%u hw_last=%u\n", 271 " current=%u, diff=%u, hw=%u hw_last=%u\n",
229 pipe, vblank->count, diff, cur_vblank, vblank->last); 272 pipe, vblank->count, diff, cur_vblank, vblank->last);