diff mbox

[5/5] drm/tegra: Implement page-flipping support

Message ID 1358178932-25505-6-git-send-email-thierry.reding@avionic-design.de
State Not Applicable, archived
Headers show

Commit Message

Thierry Reding Jan. 14, 2013, 3:55 p.m. UTC
All the necessary support bits like .mode_set_base() and VBLANK are now
available, so page-flipping case easily be implemented on top.

Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
---
 drivers/gpu/drm/tegra/dc.c  | 72 +++++++++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/tegra/drm.c |  9 ++++++
 drivers/gpu/drm/tegra/drm.h |  5 ++++
 3 files changed, 86 insertions(+)

Comments

Daniel Vetter Jan. 15, 2013, 5:53 p.m. UTC | #1
On Mon, Jan 14, 2013 at 4:55 PM, Thierry Reding
<thierry.reding@avionic-design.de> wrote:
> +static void tegra_drm_preclose(struct drm_device *drm, struct drm_file *file)
> +{
> +       struct drm_crtc *crtc;
> +
> +       list_for_each_entry(crtc, &drm->mode_config.crtc_list, head)
> +               tegra_dc_cancel_page_flip(crtc, file);
> +}
> +

Why that? If userspace dies while a flip is outstanding, it's imo ok
to execute it - otherwise there might be an accounting mismatch if the
hw still scans out the old fb, but drm believes the new one is used.
Or do I miss something?

The reason I've skimmed through the patches is to check for
implications with my modeset locking rework. Review on that would be
highly appreciated ...


Thanks, Daniel
Thierry Reding Jan. 15, 2013, 8:17 p.m. UTC | #2
On Tue, Jan 15, 2013 at 06:53:19PM +0100, Daniel Vetter wrote:
> On Mon, Jan 14, 2013 at 4:55 PM, Thierry Reding
> <thierry.reding@avionic-design.de> wrote:
> > +static void tegra_drm_preclose(struct drm_device *drm, struct drm_file *file)
> > +{
> > +       struct drm_crtc *crtc;
> > +
> > +       list_for_each_entry(crtc, &drm->mode_config.crtc_list, head)
> > +               tegra_dc_cancel_page_flip(crtc, file);
> > +}
> > +
> 
> Why that? If userspace dies while a flip is outstanding, it's imo ok
> to execute it - otherwise there might be an accounting mismatch if the
> hw still scans out the old fb, but drm believes the new one is used.
> Or do I miss something?

I looked at the shmobile driver for inspiration and they do this as
well. Doing so seemed reasonable since there'd be no file to deliver the
event to.

> The reason I've skimmed through the patches is to check for
> implications with my modeset locking rework. Review on that would be
> highly appreciated ...

I'm not sure how suited I am for review given my limited experience, but
I'll see if I can make some time to take a look.

Thierry
Daniel Vetter Jan. 16, 2013, 9:43 a.m. UTC | #3
On Tue, Jan 15, 2013 at 9:17 PM, Thierry Reding
<thierry.reding@avionic-design.de> wrote:
> On Tue, Jan 15, 2013 at 06:53:19PM +0100, Daniel Vetter wrote:
>> On Mon, Jan 14, 2013 at 4:55 PM, Thierry Reding
>> <thierry.reding@avionic-design.de> wrote:
>> > +static void tegra_drm_preclose(struct drm_device *drm, struct drm_file *file)
>> > +{
>> > +       struct drm_crtc *crtc;
>> > +
>> > +       list_for_each_entry(crtc, &drm->mode_config.crtc_list, head)
>> > +               tegra_dc_cancel_page_flip(crtc, file);
>> > +}
>> > +
>>
>> Why that? If userspace dies while a flip is outstanding, it's imo ok
>> to execute it - otherwise there might be an accounting mismatch if the
>> hw still scans out the old fb, but drm believes the new one is used.
>> Or do I miss something?
>
> I looked at the shmobile driver for inspiration and they do this as
> well. Doing so seemed reasonable since there'd be no file to deliver the
> event to.

Hm, is the code in drm_events_release not good enough? And if it's
buggy, we need to fix it. Also adding Laurent to figure out why he
added that code in shmob ...

>> The reason I've skimmed through the patches is to check for
>> implications with my modeset locking rework. Review on that would be
>> highly appreciated ...
>
> I'm not sure how suited I am for review given my limited experience, but
> I'll see if I can make some time to take a look.

The commit message should nicely explain why I've picked the design
and the various implications for drivers. So just checking whether
anything collides with your upcoming stuff would be good ...
-Daniel
Thierry Reding Jan. 16, 2013, 10:01 a.m. UTC | #4
On Wed, Jan 16, 2013 at 10:43:15AM +0100, Daniel Vetter wrote:
> On Tue, Jan 15, 2013 at 9:17 PM, Thierry Reding
> <thierry.reding@avionic-design.de> wrote:
> > On Tue, Jan 15, 2013 at 06:53:19PM +0100, Daniel Vetter wrote:
> >> On Mon, Jan 14, 2013 at 4:55 PM, Thierry Reding
> >> <thierry.reding@avionic-design.de> wrote:
> >> > +static void tegra_drm_preclose(struct drm_device *drm, struct drm_file *file)
> >> > +{
> >> > +       struct drm_crtc *crtc;
> >> > +
> >> > +       list_for_each_entry(crtc, &drm->mode_config.crtc_list, head)
> >> > +               tegra_dc_cancel_page_flip(crtc, file);
> >> > +}
> >> > +
> >>
> >> Why that? If userspace dies while a flip is outstanding, it's imo ok
> >> to execute it - otherwise there might be an accounting mismatch if the
> >> hw still scans out the old fb, but drm believes the new one is used.
> >> Or do I miss something?
> >
> > I looked at the shmobile driver for inspiration and they do this as
> > well. Doing so seemed reasonable since there'd be no file to deliver the
> > event to.
> 
> Hm, is the code in drm_events_release not good enough? And if it's
> buggy, we need to fix it. Also adding Laurent to figure out why he
> added that code in shmob ...

drm_events_release() should be enough to clean up the events, but I
suspect the reason why Laurent put that code in was that the drm_crtc
private data still has a reference to the event and needs to clear it.
Otherwise the next page flip won't be scheduled because .page_flip()
would return -EBUSY.

However, it seems like {tegra_dc,shmob_drm_crtc}_cancel_page_flip()
could both be simplified a lot and just set their event to NULL. Then
again, maybe keeping a separate reference isn't all that useful. Maybe
the better thing to do here is iterate over the list of pending VBLANK
events in *_finish_page_flip() and process each of them? That would
allow more than one user-space process to queue page flips.

> >> The reason I've skimmed through the patches is to check for
> >> implications with my modeset locking rework. Review on that would be
> >> highly appreciated ...
> >
> > I'm not sure how suited I am for review given my limited experience, but
> > I'll see if I can make some time to take a look.
> 
> The commit message should nicely explain why I've picked the design
> and the various implications for drivers. So just checking whether
> anything collides with your upcoming stuff would be good ...

Okay, I'll take a closer look.

Thierry
Daniel Vetter Jan. 16, 2013, 12:36 p.m. UTC | #5
On Wed, Jan 16, 2013 at 11:01 AM, Thierry Reding
<thierry.reding@avionic-design.de> wrote:
> drm_events_release() should be enough to clean up the events, but I
> suspect the reason why Laurent put that code in was that the drm_crtc
> private data still has a reference to the event and needs to clear it.
> Otherwise the next page flip won't be scheduled because .page_flip()
> would return -EBUSY.

Hm, indeed we seem to have a nice bug in most drivers there :(

> However, it seems like {tegra_dc,shmob_drm_crtc}_cancel_page_flip()
> could both be simplified a lot and just set their event to NULL. Then
> again, maybe keeping a separate reference isn't all that useful. Maybe
> the better thing to do here is iterate over the list of pending VBLANK
> events in *_finish_page_flip() and process each of them? That would
> allow more than one user-space process to queue page flips.

I think we need a slightly more generally useful solution, since most
drivers are currently broken. I've read a bit through the code, but
short of refcounting drm events and adding event->file_priv checks at
relevent places I don't see a sane solution ... And even that one is
rather invasive. Do you have an idea? Imo doing the cleanup in each
driver will be rather error-prone, and since usually kms clients wait
for flips to complete, also guaranteed to be little tested.
-Daniel
Rob Clark Jan. 16, 2013, 1:31 p.m. UTC | #6
On Wed, Jan 16, 2013 at 6:36 AM, Daniel Vetter <daniel@ffwll.ch> wrote:
> On Wed, Jan 16, 2013 at 11:01 AM, Thierry Reding
> <thierry.reding@avionic-design.de> wrote:
>> drm_events_release() should be enough to clean up the events, but I
>> suspect the reason why Laurent put that code in was that the drm_crtc
>> private data still has a reference to the event and needs to clear it.
>> Otherwise the next page flip won't be scheduled because .page_flip()
>> would return -EBUSY.
>
> Hm, indeed we seem to have a nice bug in most drivers there :(
>
>> However, it seems like {tegra_dc,shmob_drm_crtc}_cancel_page_flip()
>> could both be simplified a lot and just set their event to NULL. Then
>> again, maybe keeping a separate reference isn't all that useful. Maybe
>> the better thing to do here is iterate over the list of pending VBLANK
>> events in *_finish_page_flip() and process each of them? That would
>> allow more than one user-space process to queue page flips.
>
> I think we need a slightly more generally useful solution, since most
> drivers are currently broken. I've read a bit through the code, but
> short of refcounting drm events and adding event->file_priv checks at
> relevent places I don't see a sane solution ... And even that one is
> rather invasive. Do you have an idea? Imo doing the cleanup in each
> driver will be rather error-prone, and since usually kms clients wait
> for flips to complete, also guaranteed to be little tested.

I suppose we could move the *pending_vblank_event to 'struct
drm_crtc'.. I think probably all/most drivers need the same thing
anyway.  If a driver needs to do something special, it could just
never set crtc->pending_vblank_event and instead do it's own cleanup.

BR,
-R

> -Daniel
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> +41 (0) 79 365 57 48 - http://blog.ffwll.ch
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
--
To unsubscribe from this list: send the line "unsubscribe linux-tegra" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Thierry Reding Jan. 16, 2013, 6:56 p.m. UTC | #7
On Wed, Jan 16, 2013 at 01:36:17PM +0100, Daniel Vetter wrote:
> On Wed, Jan 16, 2013 at 11:01 AM, Thierry Reding
> <thierry.reding@avionic-design.de> wrote:
> > drm_events_release() should be enough to clean up the events, but I
> > suspect the reason why Laurent put that code in was that the drm_crtc
> > private data still has a reference to the event and needs to clear it.
> > Otherwise the next page flip won't be scheduled because .page_flip()
> > would return -EBUSY.
> 
> Hm, indeed we seem to have a nice bug in most drivers there :(
> 
> > However, it seems like {tegra_dc,shmob_drm_crtc}_cancel_page_flip()
> > could both be simplified a lot and just set their event to NULL. Then
> > again, maybe keeping a separate reference isn't all that useful. Maybe
> > the better thing to do here is iterate over the list of pending VBLANK
> > events in *_finish_page_flip() and process each of them? That would
> > allow more than one user-space process to queue page flips.
> 
> I think we need a slightly more generally useful solution, since most
> drivers are currently broken. I've read a bit through the code, but
> short of refcounting drm events and adding event->file_priv checks at
> relevent places I don't see a sane solution ... And even that one is
> rather invasive. Do you have an idea? Imo doing the cleanup in each
> driver will be rather error-prone, and since usually kms clients wait
> for flips to complete, also guaranteed to be little tested.

While this probably doesn't improve the situation much, maybe adding
more extensive tests to libdrm or so would help. I wrote a couple of
small programs to test vblank and plane support.

The vblank one basically generates two framebuffers with different
patterns and uses page-flipping to alternate between them. The plane
test does something similar, sets up a plane and associates a buffer
with it. It includes scaling the plane to test that functionality as
well.

Perhaps these tests could even be added to the existing libdrm tests,
but maybe having separate binaries wouldn't hurt.

Back to the original topic: should it not work to queue a page flip and
immediately exit(0) after that to test the cleanup code? I suppose if
that can be tested on all drivers we should have pretty good coverage.

Thierry
Thierry Reding Jan. 30, 2013, 9:32 a.m. UTC | #8
On Wed, Jan 16, 2013 at 01:36:17PM +0100, Daniel Vetter wrote:
> On Wed, Jan 16, 2013 at 11:01 AM, Thierry Reding
> <thierry.reding@avionic-design.de> wrote:
> > drm_events_release() should be enough to clean up the events, but I
> > suspect the reason why Laurent put that code in was that the drm_crtc
> > private data still has a reference to the event and needs to clear it.
> > Otherwise the next page flip won't be scheduled because .page_flip()
> > would return -EBUSY.
> 
> Hm, indeed we seem to have a nice bug in most drivers there :(

I think I may just recently have run into this bug on Intel hardware.
Although perhaps I just used this wrongly.

Just for the fun of it I wanted to implement Conway's Game of Life on
top of DRM/KMS. So I use two dumb buffer objects to alternately render
to. Then I wanted to use page-flipping to synchronize with VBLANK.

So the sequence is basically:

	while (!done) {
		grid_tick(grid);
		grid_draw(grid, screen);
		screen_flip(screen);
		grid_swap(grid);
	}

Where screen_flip() chooses the framebuffer and passes it to
drmModePageFlip() like so:

	int fb = screen->fb[screen->current];

	drmModePageFlip(screen->fd, screen->crtc, fb,
			DRM_MODE_PAGE_FLIP_EVENT, screen);

This runs for about 3 seconds and then hangs, so the display is no
longer updated. I've also verified that the same happens on Radeon.
But maybe I am mistaken and this isn't the proper programming sequence?

Thierry
Ville Syrjälä Jan. 30, 2013, 9:42 a.m. UTC | #9
On Wed, Jan 30, 2013 at 10:32:47AM +0100, Thierry Reding wrote:
> On Wed, Jan 16, 2013 at 01:36:17PM +0100, Daniel Vetter wrote:
> > On Wed, Jan 16, 2013 at 11:01 AM, Thierry Reding
> > <thierry.reding@avionic-design.de> wrote:
> > > drm_events_release() should be enough to clean up the events, but I
> > > suspect the reason why Laurent put that code in was that the drm_crtc
> > > private data still has a reference to the event and needs to clear it.
> > > Otherwise the next page flip won't be scheduled because .page_flip()
> > > would return -EBUSY.
> > 
> > Hm, indeed we seem to have a nice bug in most drivers there :(
> 
> I think I may just recently have run into this bug on Intel hardware.
> Although perhaps I just used this wrongly.
> 
> Just for the fun of it I wanted to implement Conway's Game of Life on
> top of DRM/KMS. So I use two dumb buffer objects to alternately render
> to. Then I wanted to use page-flipping to synchronize with VBLANK.
> 
> So the sequence is basically:
> 
> 	while (!done) {
> 		grid_tick(grid);
> 		grid_draw(grid, screen);
> 		screen_flip(screen);
> 		grid_swap(grid);
> 	}
> 
> Where screen_flip() chooses the framebuffer and passes it to
> drmModePageFlip() like so:
> 
> 	int fb = screen->fb[screen->current];
> 
> 	drmModePageFlip(screen->fd, screen->crtc, fb,
> 			DRM_MODE_PAGE_FLIP_EVENT, screen);
> 
> This runs for about 3 seconds and then hangs, so the display is no
> longer updated. I've also verified that the same happens on Radeon.
> But maybe I am mistaken and this isn't the proper programming sequence?

You asked for page flip events. Do you actually handle them in your code?
Thierry Reding Jan. 30, 2013, 11:14 a.m. UTC | #10
On Wed, Jan 30, 2013 at 11:42:40AM +0200, Ville Syrjälä wrote:
> On Wed, Jan 30, 2013 at 10:32:47AM +0100, Thierry Reding wrote:
> > On Wed, Jan 16, 2013 at 01:36:17PM +0100, Daniel Vetter wrote:
> > > On Wed, Jan 16, 2013 at 11:01 AM, Thierry Reding
> > > <thierry.reding@avionic-design.de> wrote:
> > > > drm_events_release() should be enough to clean up the events, but I
> > > > suspect the reason why Laurent put that code in was that the drm_crtc
> > > > private data still has a reference to the event and needs to clear it.
> > > > Otherwise the next page flip won't be scheduled because .page_flip()
> > > > would return -EBUSY.
> > > 
> > > Hm, indeed we seem to have a nice bug in most drivers there :(
> > 
> > I think I may just recently have run into this bug on Intel hardware.
> > Although perhaps I just used this wrongly.
> > 
> > Just for the fun of it I wanted to implement Conway's Game of Life on
> > top of DRM/KMS. So I use two dumb buffer objects to alternately render
> > to. Then I wanted to use page-flipping to synchronize with VBLANK.
> > 
> > So the sequence is basically:
> > 
> > 	while (!done) {
> > 		grid_tick(grid);
> > 		grid_draw(grid, screen);
> > 		screen_flip(screen);
> > 		grid_swap(grid);
> > 	}
> > 
> > Where screen_flip() chooses the framebuffer and passes it to
> > drmModePageFlip() like so:
> > 
> > 	int fb = screen->fb[screen->current];
> > 
> > 	drmModePageFlip(screen->fd, screen->crtc, fb,
> > 			DRM_MODE_PAGE_FLIP_EVENT, screen);
> > 
> > This runs for about 3 seconds and then hangs, so the display is no
> > longer updated. I've also verified that the same happens on Radeon.
> > But maybe I am mistaken and this isn't the proper programming sequence?
> 
> You asked for page flip events. Do you actually handle them in your code?

Duh. No I wasn't =) I suppose some queue must be running full if the
event isn't handled by calling drmHandleEvent(). Okay, this now works
properly with page-flipping.

Thanks.
Thierry
Thierry Reding Jan. 30, 2013, 11:19 a.m. UTC | #11
On Wed, Jan 30, 2013 at 12:14:36PM +0100, Thierry Reding wrote:
> On Wed, Jan 30, 2013 at 11:42:40AM +0200, Ville Syrjälä wrote:
> > On Wed, Jan 30, 2013 at 10:32:47AM +0100, Thierry Reding wrote:
> > > On Wed, Jan 16, 2013 at 01:36:17PM +0100, Daniel Vetter wrote:
> > > > On Wed, Jan 16, 2013 at 11:01 AM, Thierry Reding
> > > > <thierry.reding@avionic-design.de> wrote:
> > > > > drm_events_release() should be enough to clean up the events, but I
> > > > > suspect the reason why Laurent put that code in was that the drm_crtc
> > > > > private data still has a reference to the event and needs to clear it.
> > > > > Otherwise the next page flip won't be scheduled because .page_flip()
> > > > > would return -EBUSY.
> > > > 
> > > > Hm, indeed we seem to have a nice bug in most drivers there :(
> > > 
> > > I think I may just recently have run into this bug on Intel hardware.
> > > Although perhaps I just used this wrongly.
> > > 
> > > Just for the fun of it I wanted to implement Conway's Game of Life on
> > > top of DRM/KMS. So I use two dumb buffer objects to alternately render
> > > to. Then I wanted to use page-flipping to synchronize with VBLANK.
> > > 
> > > So the sequence is basically:
> > > 
> > > 	while (!done) {
> > > 		grid_tick(grid);
> > > 		grid_draw(grid, screen);
> > > 		screen_flip(screen);
> > > 		grid_swap(grid);
> > > 	}
> > > 
> > > Where screen_flip() chooses the framebuffer and passes it to
> > > drmModePageFlip() like so:
> > > 
> > > 	int fb = screen->fb[screen->current];
> > > 
> > > 	drmModePageFlip(screen->fd, screen->crtc, fb,
> > > 			DRM_MODE_PAGE_FLIP_EVENT, screen);
> > > 
> > > This runs for about 3 seconds and then hangs, so the display is no
> > > longer updated. I've also verified that the same happens on Radeon.
> > > But maybe I am mistaken and this isn't the proper programming sequence?
> > 
> > You asked for page flip events. Do you actually handle them in your code?
> 
> Duh. No I wasn't =) I suppose some queue must be running full if the
> event isn't handled by calling drmHandleEvent(). Okay, this now works
> properly with page-flipping.

Just in case anybody's interested, the code is here:

	https://gitorious.org/thierryreding/kmslife

Thierry
Laurent Pinchart Feb. 1, 2013, 11:01 p.m. UTC | #12
On Wednesday 16 January 2013 13:36:17 Daniel Vetter wrote:
> On Wed, Jan 16, 2013 at 11:01 AM, Thierry Reding wrote:
> > drm_events_release() should be enough to clean up the events, but I
> > suspect the reason why Laurent put that code in was that the drm_crtc
> > private data still has a reference to the event and needs to clear it.
> > Otherwise the next page flip won't be scheduled because .page_flip()
> > would return -EBUSY.
> 
> Hm, indeed we seem to have a nice bug in most drivers there :(

That's not the only reason.

drm_events_release() handles vblank events added to the vblank_event_list. 
That list only contains vblank events added by drm_queue_vblank_event(), only 
called by drm_wait_vblank(). Page flip events never get there, so they need to 
be cleaned up manually.

I wrote in the DRM documentation, in the page flipping section,

"FIXME: Could drivers that don't need to wait for rendering to complete just 
add the event to dev->vblank_event_list and let the DRM core handle 
everything, as for "normal" vertical blanking events?"

We should investigate that.

> > However, it seems like {tegra_dc,shmob_drm_crtc}_cancel_page_flip()
> > could both be simplified a lot and just set their event to NULL. Then
> > again, maybe keeping a separate reference isn't all that useful. Maybe
> > the better thing to do here is iterate over the list of pending VBLANK
> > events in *_finish_page_flip() and process each of them? That would
> > allow more than one user-space process to queue page flips.
> 
> I think we need a slightly more generally useful solution, since most
> drivers are currently broken. I've read a bit through the code, but
> short of refcounting drm events and adding event->file_priv checks at
> relevent places I don't see a sane solution ... And even that one is
> rather invasive. Do you have an idea? Imo doing the cleanup in each
> driver will be rather error-prone, and since usually kms clients wait
> for flips to complete, also guaranteed to be little tested.
Laurent Pinchart Feb. 1, 2013, 11:05 p.m. UTC | #13
Hi Thierry,

On Wednesday 16 January 2013 19:56:06 Thierry Reding wrote:
> On Wed, Jan 16, 2013 at 01:36:17PM +0100, Daniel Vetter wrote:
> > On Wed, Jan 16, 2013 at 11:01 AM, Thierry Reding wrote:
> > > drm_events_release() should be enough to clean up the events, but I
> > > suspect the reason why Laurent put that code in was that the drm_crtc
> > > private data still has a reference to the event and needs to clear it.
> > > Otherwise the next page flip won't be scheduled because .page_flip()
> > > would return -EBUSY.
> > 
> > Hm, indeed we seem to have a nice bug in most drivers there :(
> > 
> > > However, it seems like {tegra_dc,shmob_drm_crtc}_cancel_page_flip()
> > > could both be simplified a lot and just set their event to NULL. Then
> > > again, maybe keeping a separate reference isn't all that useful. Maybe
> > > the better thing to do here is iterate over the list of pending VBLANK
> > > events in *_finish_page_flip() and process each of them? That would
> > > allow more than one user-space process to queue page flips.
> > 
> > I think we need a slightly more generally useful solution, since most
> > drivers are currently broken. I've read a bit through the code, but
> > short of refcounting drm events and adding event->file_priv checks at
> > relevent places I don't see a sane solution ... And even that one is
> > rather invasive. Do you have an idea? Imo doing the cleanup in each
> > driver will be rather error-prone, and since usually kms clients wait
> > for flips to complete, also guaranteed to be little tested.
> 
> While this probably doesn't improve the situation much, maybe adding
> more extensive tests to libdrm or so would help. I wrote a couple of
> small programs to test vblank and plane support.
> 
> The vblank one basically generates two framebuffers with different
> patterns and uses page-flipping to alternate between them. The plane
> test does something similar, sets up a plane and associates a buffer
> with it. It includes scaling the plane to test that functionality as
> well.
> 
> Perhaps these tests could even be added to the existing libdrm tests,
> but maybe having separate binaries wouldn't hurt.

Further cleanup of the modetest application is somewhere on my to-do list (but 
probably so low that I'll never get to it unless there's a real incentive 
;-)). It's a good candidate for more page flip testing (there's basic page 
flip support there already).

> Back to the original topic: should it not work to queue a page flip and
> immediately exit(0) after that to test the cleanup code? I suppose if
> that can be tested on all drivers we should have pretty good coverage.

Maybe we need some kind of compliance test suite tool ?
Daniel Vetter Feb. 11, 2013, 6 p.m. UTC | #14
On Sat, Feb 2, 2013 at 12:05 AM, Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
>> Back to the original topic: should it not work to queue a page flip and
>> immediately exit(0) after that to test the cleanup code? I suppose if
>> that can be tested on all drivers we should have pretty good coverage.
>
> Maybe we need some kind of compliance test suite tool ?

kms_flip from our intel-specific testsuite is probably the most
paranoid thing for testing page flips out there:

http://cgit.freedesktop.org/xorg/app/intel-gpu-tools/tree/tests/kms_flip.c

Cheers, Daniel
diff mbox

Patch

diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index 3aa7ccc..ce4e14a 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -161,7 +161,78 @@  void tegra_dc_disable_vblank(struct tegra_dc *dc)
 	spin_unlock_irqrestore(&dc->lock, flags);
 }
 
+static void tegra_dc_finish_page_flip(struct tegra_dc *dc)
+{
+	struct drm_pending_vblank_event *event;
+	struct drm_device *drm = dc->base.dev;
+	unsigned long flags;
+	struct timeval now;
+
+	spin_lock_irqsave(&drm->event_lock, flags);
+	event = dc->event;
+	dc->event = NULL;
+	spin_unlock_irqrestore(&drm->event_lock, flags);
+
+	if (!event)
+		return;
+
+	event->event.sequence = drm_vblank_count_and_time(drm, dc->pipe, &now);
+	event->event.tv_sec = now.tv_sec;
+	event->event.tv_usec = now.tv_usec;
+
+	spin_lock_irqsave(&drm->event_lock, flags);
+	list_add_tail(&event->base.link, &event->base.file_priv->event_list);
+	wake_up_interruptible(&event->base.file_priv->event_wait);
+	spin_unlock_irqrestore(&drm->event_lock, flags);
+
+	drm_vblank_put(drm, dc->pipe);
+}
+
+void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file)
+{
+	struct tegra_dc *dc = to_tegra_dc(crtc);
+	struct drm_device *drm = crtc->dev;
+	unsigned long flags;
+
+	spin_lock_irqsave(&drm->event_lock, flags);
+
+	if (dc->event && dc->event->base.file_priv == file) {
+		dc->event->base.destroy(&dc->event->base);
+		drm_vblank_put(drm, dc->pipe);
+		dc->event = NULL;
+	}
+
+	spin_unlock_irqrestore(&drm->event_lock, flags);
+}
+
+static int tegra_dc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
+			      struct drm_pending_vblank_event *event)
+{
+	struct tegra_framebuffer *newfb = to_tegra_fb(fb);
+	struct tegra_dc *dc = to_tegra_dc(crtc);
+	struct drm_device *drm = crtc->dev;
+	unsigned long flags;
+
+	if (dc->event)
+		return -EBUSY;
+
+	tegra_dc_set_base(dc, 0, 0, newfb);
+
+	if (event) {
+		event->pipe = dc->pipe;
+
+		spin_lock_irqsave(&drm->event_lock, flags);
+		dc->event = event;
+		spin_unlock_irqrestore(&drm->event_lock, flags);
+
+		drm_vblank_get(drm, dc->pipe);
+	}
+
+	return 0;
+}
+
 static const struct drm_crtc_funcs tegra_crtc_funcs = {
+	.page_flip = tegra_dc_page_flip,
 	.set_config = drm_crtc_helper_set_config,
 	.destroy = drm_crtc_cleanup,
 };
@@ -556,6 +627,7 @@  static irqreturn_t tegra_dc_irq(int irq, void *data)
 		dev_dbg(dc->dev, "%s(): vertical blank\n", __func__);
 		*/
 		drm_handle_vblank(dc->base.dev, dc->pipe);
+		tegra_dc_finish_page_flip(dc);
 	}
 
 	if (status & (WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT)) {
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
index 62f8121..7bab784 100644
--- a/drivers/gpu/drm/tegra/drm.c
+++ b/drivers/gpu/drm/tegra/drm.c
@@ -129,11 +129,20 @@  static void tegra_drm_disable_vblank(struct drm_device *drm, int pipe)
 		tegra_dc_disable_vblank(dc);
 }
 
+static void tegra_drm_preclose(struct drm_device *drm, struct drm_file *file)
+{
+	struct drm_crtc *crtc;
+
+	list_for_each_entry(crtc, &drm->mode_config.crtc_list, head)
+		tegra_dc_cancel_page_flip(crtc, file);
+}
+
 struct drm_driver tegra_drm_driver = {
 	.driver_features = DRIVER_BUS_PLATFORM | DRIVER_MODESET | DRIVER_GEM,
 	.load = tegra_drm_load,
 	.unload = tegra_drm_unload,
 	.open = tegra_drm_open,
+	.preclose = tegra_drm_preclose,
 	.lastclose = tegra_drm_lastclose,
 
 	.get_vblank_counter = drm_vblank_count,
diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h
index bb5e9d3..3aa21b1 100644
--- a/drivers/gpu/drm/tegra/drm.h
+++ b/drivers/gpu/drm/tegra/drm.h
@@ -103,6 +103,9 @@  struct tegra_dc {
 	struct drm_info_list *debugfs_files;
 	struct drm_minor *minor;
 	struct dentry *debugfs;
+
+	/* page-flip handling */
+	struct drm_pending_vblank_event *event;
 };
 
 static inline struct tegra_dc *host1x_client_to_dc(struct host1x_client *client)
@@ -152,6 +155,8 @@  extern int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
 				 const struct tegra_dc_window *window);
 extern void tegra_dc_enable_vblank(struct tegra_dc *dc);
 extern void tegra_dc_disable_vblank(struct tegra_dc *dc);
+extern void tegra_dc_cancel_page_flip(struct drm_crtc *crtc,
+				      struct drm_file *file);
 
 struct display {
 	unsigned int width;