diff options
-rw-r--r-- | drivers/gpu/drm/drm_irq.c | 43 |
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); |