diff mbox

drm/etnaviv: correct timeout calculation

Message ID 20180309112149.9801-1-l.stach@pengutronix.de (mailing list archive)
State New, archived
Headers show

Commit Message

Lucas Stach March 9, 2018, 11:21 a.m. UTC
The old way did clamp the jiffy conversion and thus caused the timeouts
to become negative after some time. Also it didn't work with userspace
which actually fills the upper 32bits of the 64bit timestamp value.

Fix this by using the solution developed and tested by Russell.

Suggested-by: Russell King <linux@armlinux.org.uk>
Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
---
 drivers/gpu/drm/etnaviv/etnaviv_drv.h | 25 +++++++++++++++++--------
 1 file changed, 17 insertions(+), 8 deletions(-)

Comments

Russell King (Oracle) March 9, 2018, 11:44 a.m. UTC | #1
Hi Lucas,

Please retain my authorship of my patch, which was sent on 23 Oct 2017.
The patch you have below is 100% identical to that which I sent.

You should also point out, as per the follow-on discussion, that using
clock_gettime() on 32-bit systems will not work once the time it
reports wraps - so something like the comment I suggested in a follow
up patch:

+ * Etnaviv timeouts are specified wrt CLOCK_MONOTONIC, not jiffies.
+ * We need to calculate the timeout in terms of number of jiffies
+ * between the specified timeout and the current CLOCK_MONOTONIC time.
+ * Note: clock_gettime() is 32-bit on 32-bit arch.  Using 64-bit
+ * timespec math here just means that when a wrap occurs, the
+ * specified timeout goes into the past and we can't request a
+ * timeout in the future: IOW, the code breaks.

would be sensible either in the commit message or the code.

On Fri, Mar 09, 2018 at 12:21:49PM +0100, Lucas Stach wrote:
> The old way did clamp the jiffy conversion and thus caused the timeouts
> to become negative after some time. Also it didn't work with userspace
> which actually fills the upper 32bits of the 64bit timestamp value.
> 
> Fix this by using the solution developed and tested by Russell.
> 
> Suggested-by: Russell King <linux@armlinux.org.uk>
> Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
> ---
>  drivers/gpu/drm/etnaviv/etnaviv_drv.h | 25 +++++++++++++++++--------
>  1 file changed, 17 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.h b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
> index ddb17ee565e9..17a43da98fb9 100644
> --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.h
> +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
> @@ -26,6 +26,7 @@
>  #include <linux/pm_runtime.h>
>  #include <linux/slab.h>
>  #include <linux/list.h>
> +#include <linux/time64.h>
>  #include <linux/types.h>
>  #include <linux/sizes.h>
>  
> @@ -132,19 +133,27 @@ static inline bool fence_after_eq(u32 a, u32 b)
>  	return (s32)(a - b) >= 0;
>  }
>  
> +/*
> + * Etnaviv timeouts are specified wrt CLOCK_MONOTONIC, not jiffies.
> + * We need to calculate the timeout in terms of number of jiffies
> + * between the specified timeout and the current CLOCK_MONOTONIC time.
> + */
>  static inline unsigned long etnaviv_timeout_to_jiffies(
>  	const struct timespec *timeout)
>  {
> -	unsigned long timeout_jiffies = timespec_to_jiffies(timeout);
> -	unsigned long start_jiffies = jiffies;
> -	unsigned long remaining_jiffies;
> +	struct timespec64 ts, to;
> +
> +	to = timespec_to_timespec64(*timeout);
> +
> +	ktime_get_ts64(&ts);
> +
> +	/* timeouts before "now" have already expired */
> +	if (timespec64_compare(&to, &ts) <= 0)
> +		return 0;
>  
> -	if (time_after(start_jiffies, timeout_jiffies))
> -		remaining_jiffies = 0;
> -	else
> -		remaining_jiffies = timeout_jiffies - start_jiffies;
> +	ts = timespec64_sub(to, ts);
>  
> -	return remaining_jiffies;
> +	return timespec64_to_jiffies(&ts);
>  }
>  
>  #endif /* __ETNAVIV_DRV_H__ */
> -- 
> 2.16.1
>
Lucas Stach March 9, 2018, 11:52 a.m. UTC | #2
Hi Russell,

Am Freitag, den 09.03.2018, 11:44 +0000 schrieb Russell King - ARM Linux:
> Hi Lucas,
> 
> Please retain my authorship of my patch, which was sent on 23 Oct 2017.
> The patch you have below is 100% identical to that which I sent.

I'll gladly do so if you provide me a proper Signed-off-by for this
patch, which was missing from your 23 Oct 2017 submission.

> You should also point out, as per the follow-on discussion, that using
> clock_gettime() on 32-bit systems will not work once the time it
> reports wraps - so something like the comment I suggested in a follow
> up patch:
> 
> + * Etnaviv timeouts are specified wrt CLOCK_MONOTONIC, not jiffies.
> + * We need to calculate the timeout in terms of number of jiffies
> + * between the specified timeout and the current CLOCK_MONOTONIC time.
> + * Note: clock_gettime() is 32-bit on 32-bit arch.  Using 64-bit
> + * timespec math here just means that when a wrap occurs, the
> + * specified timeout goes into the past and we can't request a
> + * timeout in the future: IOW, the code breaks.
> 
> would be sensible either in the commit message or the code.

I'll add it to the commit message, as I think the discussion with Arnd
established that this is a very theoretical risk, not likely to be hit
in practice.

Regards,
Lucas

> On Fri, Mar 09, 2018 at 12:21:49PM +0100, Lucas Stach wrote:
> > The old way did clamp the jiffy conversion and thus caused the timeouts
> > to become negative after some time. Also it didn't work with userspace
> > which actually fills the upper 32bits of the 64bit timestamp value.
> > 
> > Fix this by using the solution developed and tested by Russell.
> > 
> > > > Suggested-by: Russell King <linux@armlinux.org.uk>
> > > > Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
> > ---
> >  drivers/gpu/drm/etnaviv/etnaviv_drv.h | 25 +++++++++++++++++--------
> >  1 file changed, 17 insertions(+), 8 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.h b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
> > index ddb17ee565e9..17a43da98fb9 100644
> > --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.h
> > +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
> > @@ -26,6 +26,7 @@
> >  #include <linux/pm_runtime.h>
> >  #include <linux/slab.h>
> >  #include <linux/list.h>
> > +#include <linux/time64.h>
> >  #include <linux/types.h>
> >  #include <linux/sizes.h>
> >  
> > @@ -132,19 +133,27 @@ static inline bool fence_after_eq(u32 a, u32 b)
> > > >  	return (s32)(a - b) >= 0;
> >  }
> >  
> > +/*
> > + * Etnaviv timeouts are specified wrt CLOCK_MONOTONIC, not jiffies.
> > + * We need to calculate the timeout in terms of number of jiffies
> > + * between the specified timeout and the current CLOCK_MONOTONIC time.
> > + */
> >  static inline unsigned long etnaviv_timeout_to_jiffies(
> > > >  	const struct timespec *timeout)
> >  {
> > > > -	unsigned long timeout_jiffies = timespec_to_jiffies(timeout);
> > > > -	unsigned long start_jiffies = jiffies;
> > > > -	unsigned long remaining_jiffies;
> > > > +	struct timespec64 ts, to;
> > +
> > > > +	to = timespec_to_timespec64(*timeout);
> > +
> > > > +	ktime_get_ts64(&ts);
> > +
> > > > +	/* timeouts before "now" have already expired */
> > > > +	if (timespec64_compare(&to, &ts) <= 0)
> > > > +		return 0;
> >  
> > > > -	if (time_after(start_jiffies, timeout_jiffies))
> > > > -		remaining_jiffies = 0;
> > > > -	else
> > > > -		remaining_jiffies = timeout_jiffies - start_jiffies;
> > > > +	ts = timespec64_sub(to, ts);
> >  
> > > > -	return remaining_jiffies;
> > > > +	return timespec64_to_jiffies(&ts);
> >  }
> >  
> >  #endif /* __ETNAVIV_DRV_H__ */
> > -- 
> > 2.16.1
> > 
> 
>
Russell King (Oracle) March 9, 2018, 12:34 p.m. UTC | #3
On Fri, Mar 09, 2018 at 12:52:40PM +0100, Lucas Stach wrote:
> Hi Russell,
> 
> Am Freitag, den 09.03.2018, 11:44 +0000 schrieb Russell King - ARM Linux:
> > Hi Lucas,
> > 
> > Please retain my authorship of my patch, which was sent on 23 Oct 2017.
> > The patch you have below is 100% identical to that which I sent.
> 
> I'll gladly do so if you provide me a proper Signed-off-by for this
> patch, which was missing from your 23 Oct 2017 submission.

It wasn't a submission, but was for discussion and I provided two
variants.

However, by doing what you've done, you're effectively claiming
authorship of my work, and as works are copyrighted, that's really
not nice.  Unfortunately, the Linux community has tied itself in
knots over the "author must sign-off on the patch" despite DCO (b)
existing, and DCO (b) specifically allows for patches that are not
authored by the submitter to be incorporated into the kernel.

If you take the authorship and the manufactured sign-off requirements
together, then effectively no one has the ability to submit code
that they did not author.

Nevertheless, for this patch,

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>

> 
> > You should also point out, as per the follow-on discussion, that using
> > clock_gettime() on 32-bit systems will not work once the time it
> > reports wraps - so something like the comment I suggested in a follow
> > up patch:
> > 
> > + * Etnaviv timeouts are specified wrt CLOCK_MONOTONIC, not jiffies.
> > + * We need to calculate the timeout in terms of number of jiffies
> > + * between the specified timeout and the current CLOCK_MONOTONIC time.
> > + * Note: clock_gettime() is 32-bit on 32-bit arch.  Using 64-bit
> > + * timespec math here just means that when a wrap occurs, the
> > + * specified timeout goes into the past and we can't request a
> > + * timeout in the future: IOW, the code breaks.
> > 
> > would be sensible either in the commit message or the code.
> 
> I'll add it to the commit message, as I think the discussion with Arnd
> established that this is a very theoretical risk, not likely to be hit
> in practice.

True, it's only likely to be hit if a system is up for 68 years, but
it's still worth documenting.
diff mbox

Patch

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.h b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
index ddb17ee565e9..17a43da98fb9 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
@@ -26,6 +26,7 @@ 
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>
 #include <linux/list.h>
+#include <linux/time64.h>
 #include <linux/types.h>
 #include <linux/sizes.h>
 
@@ -132,19 +133,27 @@  static inline bool fence_after_eq(u32 a, u32 b)
 	return (s32)(a - b) >= 0;
 }
 
+/*
+ * Etnaviv timeouts are specified wrt CLOCK_MONOTONIC, not jiffies.
+ * We need to calculate the timeout in terms of number of jiffies
+ * between the specified timeout and the current CLOCK_MONOTONIC time.
+ */
 static inline unsigned long etnaviv_timeout_to_jiffies(
 	const struct timespec *timeout)
 {
-	unsigned long timeout_jiffies = timespec_to_jiffies(timeout);
-	unsigned long start_jiffies = jiffies;
-	unsigned long remaining_jiffies;
+	struct timespec64 ts, to;
+
+	to = timespec_to_timespec64(*timeout);
+
+	ktime_get_ts64(&ts);
+
+	/* timeouts before "now" have already expired */
+	if (timespec64_compare(&to, &ts) <= 0)
+		return 0;
 
-	if (time_after(start_jiffies, timeout_jiffies))
-		remaining_jiffies = 0;
-	else
-		remaining_jiffies = timeout_jiffies - start_jiffies;
+	ts = timespec64_sub(to, ts);
 
-	return remaining_jiffies;
+	return timespec64_to_jiffies(&ts);
 }
 
 #endif /* __ETNAVIV_DRV_H__ */