|
|
a86f9a6 |
From 424f582d0ec7f206dcc59d34c9a2fa1c8087a8aa Mon Sep 17 00:00:00 2001
|
|
|
a86f9a6 |
From: Daniel Vetter <daniel.vetter@ffwll.ch>
|
|
|
a86f9a6 |
Date: Tue, 10 Nov 2015 17:37:31 +0100
|
|
|
a86f9a6 |
Subject: [PATCH] drm/nouveau: Fix pre-nv50 pageflip events (v4)
|
|
|
a86f9a6 |
MIME-Version: 1.0
|
|
|
a86f9a6 |
Content-Type: text/plain; charset=UTF-8
|
|
|
a86f9a6 |
Content-Transfer-Encoding: 8bit
|
|
|
a86f9a6 |
|
|
|
a86f9a6 |
Apparently pre-nv50 pageflip events happen before the actual vblank
|
|
|
a86f9a6 |
period. Therefore that functionality got semi-disabled in
|
|
|
a86f9a6 |
|
|
|
a86f9a6 |
commit af4870e406126b7ac0ae7c7ce5751f25ebe60f28
|
|
|
a86f9a6 |
Author: Mario Kleiner <mario.kleiner.de@gmail.com>
|
|
|
a86f9a6 |
Date: Tue May 13 00:42:08 2014 +0200
|
|
|
a86f9a6 |
|
|
|
a86f9a6 |
drm/nouveau/kms/nv04-nv40: fix pageflip events via special case.
|
|
|
a86f9a6 |
|
|
|
a86f9a6 |
Unfortunately that hack got uprooted in
|
|
|
a86f9a6 |
|
|
|
a86f9a6 |
commit cc1ef118fc099295ae6aabbacc8af94d8d8885eb
|
|
|
a86f9a6 |
Author: Thierry Reding <treding@nvidia.com>
|
|
|
a86f9a6 |
Date: Wed Aug 12 17:00:31 2015 +0200
|
|
|
a86f9a6 |
|
|
|
a86f9a6 |
drm/irq: Make pipe unsigned and name consistent
|
|
|
a86f9a6 |
|
|
|
a86f9a6 |
Triggering a warning when trying to sample the vblank timestamp for a
|
|
|
a86f9a6 |
non-existing pipe. There's a few ways to fix this:
|
|
|
a86f9a6 |
|
|
|
a86f9a6 |
- Open-code the old behaviour, which just enshrines this slight
|
|
|
a86f9a6 |
breakage of the userspace ABI.
|
|
|
a86f9a6 |
|
|
|
a86f9a6 |
- Revert Mario's commit and again inflict broken timestamps, again not
|
|
|
a86f9a6 |
pretty.
|
|
|
a86f9a6 |
|
|
|
a86f9a6 |
- Fix this for real by delaying the pageflip TS until the next vblank
|
|
|
a86f9a6 |
interrupt, thereby making it accurate.
|
|
|
a86f9a6 |
|
|
|
a86f9a6 |
This patch implements the third option. Since having a page flip
|
|
|
a86f9a6 |
interrupt that happens when the pageflip gets armed and not when it
|
|
|
a86f9a6 |
completes in the next vblank seems to be fairly common (older i915 hw
|
|
|
a86f9a6 |
works very similarly) create a new helper to arm vblank events for
|
|
|
a86f9a6 |
such drivers.
|
|
|
a86f9a6 |
|
|
|
a86f9a6 |
v2 (Mario Kleiner):
|
|
|
a86f9a6 |
- Fix function prototypes in drmP.h
|
|
|
a86f9a6 |
- Add missing vblank_put() for pageflip completion without
|
|
|
a86f9a6 |
pageflip event.
|
|
|
a86f9a6 |
- Initialize sequence number for queued pageflip event to avoid
|
|
|
a86f9a6 |
trouble in drm_handle_vblank_events().
|
|
|
a86f9a6 |
- Remove dead code and spelling fix.
|
|
|
a86f9a6 |
|
|
|
a86f9a6 |
v3 (Mario Kleiner):
|
|
|
a86f9a6 |
- Add a signed-off-by and cc stable tag per Ilja's advice.
|
|
|
a86f9a6 |
|
|
|
a86f9a6 |
v4 (Thierry Reding):
|
|
|
a86f9a6 |
- Fix kerneldoc typo, discovered by Michel Dänzer
|
|
|
a86f9a6 |
- Rearrange tags and changelog
|
|
|
a86f9a6 |
|
|
|
a86f9a6 |
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=106431
|
|
|
a86f9a6 |
Cc: Thierry Reding <treding@nvidia.com>
|
|
|
a86f9a6 |
Cc: Mario Kleiner <mario.kleiner.de@gmail.com>
|
|
|
a86f9a6 |
Acked-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
a86f9a6 |
Cc: Ilia Mirkin <imirkin@alum.mit.edu>
|
|
|
a86f9a6 |
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
|
|
|
a86f9a6 |
Reviewed-by: Mario Kleiner <mario.kleiner.de@gmail.com>
|
|
|
a86f9a6 |
Cc: stable@vger.kernel.org # v4.3
|
|
|
a86f9a6 |
Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com>
|
|
|
a86f9a6 |
Signed-off-by: Thierry Reding <treding@nvidia.com>
|
|
|
a86f9a6 |
Signed-off-by: Dave Airlie <airlied@redhat.com>
|
|
|
a86f9a6 |
---
|
|
|
a86f9a6 |
drivers/gpu/drm/drm_irq.c | 54 ++++++++++++++++++++++++++++++-
|
|
|
a86f9a6 |
drivers/gpu/drm/nouveau/nouveau_display.c | 19 ++++++-----
|
|
|
a86f9a6 |
include/drm/drmP.h | 4 +++
|
|
|
a86f9a6 |
3 files changed, 68 insertions(+), 9 deletions(-)
|
|
|
a86f9a6 |
|
|
|
a86f9a6 |
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
|
|
|
a86f9a6 |
index 22d207e211e7..c5f20e41dcc6 100644
|
|
|
a86f9a6 |
--- a/drivers/gpu/drm/drm_irq.c
|
|
|
a86f9a6 |
+++ b/drivers/gpu/drm/drm_irq.c
|
|
|
a86f9a6 |
@@ -944,7 +944,8 @@ static void send_vblank_event(struct drm_device *dev,
|
|
|
a86f9a6 |
struct drm_pending_vblank_event *e,
|
|
|
a86f9a6 |
unsigned long seq, struct timeval *now)
|
|
|
a86f9a6 |
{
|
|
|
a86f9a6 |
- WARN_ON_SMP(!spin_is_locked(&dev->event_lock));
|
|
|
a86f9a6 |
+ assert_spin_locked(&dev->event_lock);
|
|
|
a86f9a6 |
+
|
|
|
a86f9a6 |
e->event.sequence = seq;
|
|
|
a86f9a6 |
e->event.tv_sec = now->tv_sec;
|
|
|
a86f9a6 |
e->event.tv_usec = now->tv_usec;
|
|
|
a86f9a6 |
@@ -957,6 +958,57 @@ static void send_vblank_event(struct drm_device *dev,
|
|
|
a86f9a6 |
}
|
|
|
a86f9a6 |
|
|
|
a86f9a6 |
/**
|
|
|
a86f9a6 |
+ * drm_arm_vblank_event - arm vblank event after pageflip
|
|
|
a86f9a6 |
+ * @dev: DRM device
|
|
|
a86f9a6 |
+ * @pipe: CRTC index
|
|
|
a86f9a6 |
+ * @e: the event to prepare to send
|
|
|
a86f9a6 |
+ *
|
|
|
a86f9a6 |
+ * A lot of drivers need to generate vblank events for the very next vblank
|
|
|
a86f9a6 |
+ * interrupt. For example when the page flip interrupt happens when the page
|
|
|
a86f9a6 |
+ * flip gets armed, but not when it actually executes within the next vblank
|
|
|
a86f9a6 |
+ * period. This helper function implements exactly the required vblank arming
|
|
|
a86f9a6 |
+ * behaviour.
|
|
|
a86f9a6 |
+ *
|
|
|
a86f9a6 |
+ * Caller must hold event lock. Caller must also hold a vblank reference for
|
|
|
a86f9a6 |
+ * the event @e, which will be dropped when the next vblank arrives.
|
|
|
a86f9a6 |
+ *
|
|
|
a86f9a6 |
+ * This is the legacy version of drm_crtc_arm_vblank_event().
|
|
|
a86f9a6 |
+ */
|
|
|
a86f9a6 |
+void drm_arm_vblank_event(struct drm_device *dev, unsigned int pipe,
|
|
|
a86f9a6 |
+ struct drm_pending_vblank_event *e)
|
|
|
a86f9a6 |
+{
|
|
|
a86f9a6 |
+ assert_spin_locked(&dev->event_lock);
|
|
|
a86f9a6 |
+
|
|
|
a86f9a6 |
+ e->pipe = pipe;
|
|
|
a86f9a6 |
+ e->event.sequence = drm_vblank_count(dev, pipe);
|
|
|
a86f9a6 |
+ list_add_tail(&e->base.link, &dev->vblank_event_list);
|
|
|
a86f9a6 |
+}
|
|
|
a86f9a6 |
+EXPORT_SYMBOL(drm_arm_vblank_event);
|
|
|
a86f9a6 |
+
|
|
|
a86f9a6 |
+/**
|
|
|
a86f9a6 |
+ * drm_crtc_arm_vblank_event - arm vblank event after pageflip
|
|
|
a86f9a6 |
+ * @crtc: the source CRTC of the vblank event
|
|
|
a86f9a6 |
+ * @e: the event to send
|
|
|
a86f9a6 |
+ *
|
|
|
a86f9a6 |
+ * A lot of drivers need to generate vblank events for the very next vblank
|
|
|
a86f9a6 |
+ * interrupt. For example when the page flip interrupt happens when the page
|
|
|
a86f9a6 |
+ * flip gets armed, but not when it actually executes within the next vblank
|
|
|
a86f9a6 |
+ * period. This helper function implements exactly the required vblank arming
|
|
|
a86f9a6 |
+ * behaviour.
|
|
|
a86f9a6 |
+ *
|
|
|
a86f9a6 |
+ * Caller must hold event lock. Caller must also hold a vblank reference for
|
|
|
a86f9a6 |
+ * the event @e, which will be dropped when the next vblank arrives.
|
|
|
a86f9a6 |
+ *
|
|
|
a86f9a6 |
+ * This is the native KMS version of drm_arm_vblank_event().
|
|
|
a86f9a6 |
+ */
|
|
|
a86f9a6 |
+void drm_crtc_arm_vblank_event(struct drm_crtc *crtc,
|
|
|
a86f9a6 |
+ struct drm_pending_vblank_event *e)
|
|
|
a86f9a6 |
+{
|
|
|
a86f9a6 |
+ drm_arm_vblank_event(crtc->dev, drm_crtc_index(crtc), e);
|
|
|
a86f9a6 |
+}
|
|
|
a86f9a6 |
+EXPORT_SYMBOL(drm_crtc_arm_vblank_event);
|
|
|
a86f9a6 |
+
|
|
|
a86f9a6 |
+/**
|
|
|
a86f9a6 |
* drm_send_vblank_event - helper to send vblank event after pageflip
|
|
|
a86f9a6 |
* @dev: DRM device
|
|
|
a86f9a6 |
* @pipe: CRTC index
|
|
|
a86f9a6 |
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
|
|
|
a86f9a6 |
index e905c00acf1a..54183bcca48f 100644
|
|
|
a86f9a6 |
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
|
|
|
a86f9a6 |
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
|
|
|
a86f9a6 |
@@ -827,7 +827,6 @@ nouveau_finish_page_flip(struct nouveau_channel *chan,
|
|
|
a86f9a6 |
struct drm_device *dev = drm->dev;
|
|
|
a86f9a6 |
struct nouveau_page_flip_state *s;
|
|
|
a86f9a6 |
unsigned long flags;
|
|
|
a86f9a6 |
- int crtcid = -1;
|
|
|
a86f9a6 |
|
|
|
a86f9a6 |
spin_lock_irqsave(&dev->event_lock, flags);
|
|
|
a86f9a6 |
|
|
|
a86f9a6 |
@@ -839,15 +838,19 @@ nouveau_finish_page_flip(struct nouveau_channel *chan,
|
|
|
a86f9a6 |
|
|
|
a86f9a6 |
s = list_first_entry(&fctx->flip, struct nouveau_page_flip_state, head);
|
|
|
a86f9a6 |
if (s->event) {
|
|
|
a86f9a6 |
- /* Vblank timestamps/counts are only correct on >= NV-50 */
|
|
|
a86f9a6 |
- if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA)
|
|
|
a86f9a6 |
- crtcid = s->crtc;
|
|
|
a86f9a6 |
+ if (drm->device.info.family < NV_DEVICE_INFO_V0_TESLA) {
|
|
|
a86f9a6 |
+ drm_arm_vblank_event(dev, s->crtc, s->event);
|
|
|
a86f9a6 |
+ } else {
|
|
|
a86f9a6 |
+ drm_send_vblank_event(dev, s->crtc, s->event);
|
|
|
a86f9a6 |
|
|
|
a86f9a6 |
- drm_send_vblank_event(dev, crtcid, s->event);
|
|
|
a86f9a6 |
+ /* Give up ownership of vblank for page-flipped crtc */
|
|
|
a86f9a6 |
+ drm_vblank_put(dev, s->crtc);
|
|
|
a86f9a6 |
+ }
|
|
|
a86f9a6 |
+ }
|
|
|
a86f9a6 |
+ else {
|
|
|
a86f9a6 |
+ /* Give up ownership of vblank for page-flipped crtc */
|
|
|
a86f9a6 |
+ drm_vblank_put(dev, s->crtc);
|
|
|
a86f9a6 |
}
|
|
|
a86f9a6 |
-
|
|
|
a86f9a6 |
- /* Give up ownership of vblank for page-flipped crtc */
|
|
|
a86f9a6 |
- drm_vblank_put(dev, s->crtc);
|
|
|
a86f9a6 |
|
|
|
a86f9a6 |
list_del(&s->head);
|
|
|
a86f9a6 |
if (ps)
|
|
|
a86f9a6 |
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
|
|
|
a86f9a6 |
index 8b5ce7c5d9bb..c98f01046bd0 100644
|
|
|
a86f9a6 |
--- a/include/drm/drmP.h
|
|
|
a86f9a6 |
+++ b/include/drm/drmP.h
|
|
|
a86f9a6 |
@@ -932,6 +932,10 @@ extern void drm_send_vblank_event(struct drm_device *dev, unsigned int pipe,
|
|
|
a86f9a6 |
struct drm_pending_vblank_event *e);
|
|
|
a86f9a6 |
extern void drm_crtc_send_vblank_event(struct drm_crtc *crtc,
|
|
|
a86f9a6 |
struct drm_pending_vblank_event *e);
|
|
|
a86f9a6 |
+extern void drm_arm_vblank_event(struct drm_device *dev, unsigned int pipe,
|
|
|
a86f9a6 |
+ struct drm_pending_vblank_event *e);
|
|
|
a86f9a6 |
+extern void drm_crtc_arm_vblank_event(struct drm_crtc *crtc,
|
|
|
a86f9a6 |
+ struct drm_pending_vblank_event *e);
|
|
|
a86f9a6 |
extern bool drm_handle_vblank(struct drm_device *dev, unsigned int pipe);
|
|
|
a86f9a6 |
extern bool drm_crtc_handle_vblank(struct drm_crtc *crtc);
|
|
|
a86f9a6 |
extern int drm_vblank_get(struct drm_device *dev, unsigned int pipe);
|
|
|
a86f9a6 |
--
|
|
|
a86f9a6 |
2.5.0
|
|
|
a86f9a6 |
|