diff mbox series

[RFC,1/1] lib: sbi_timer: Added a blocking wait function that waits until a certain condition is true or timeout occurs

Message ID 20220629134257.374341-2-adnan.chowdhury@sifive.com
State Superseded
Headers show
Series Added a blocking wait function that waits until a certain condition is true or timeout occurs | expand

Commit Message

Adnan Rahman Chowdhury June 29, 2022, 1:42 p.m. UTC
Motivation: Suppose a peripheral needs to be configured to transmit data.
There is an SFR bit which indicates that the peripheral is ready to transmit.
The firmware should check the bit and will only transmit data when the
peripheral is ready. When the firmware starts polling the SFR, the peripheral
could be busy transmitting/receiving other data so the firmware must wait
till that completes. Assuming that there is no other way, the
firmware shouldn't wait indefinitely.

The function sbi_timer_waitms_until() will constantly check whether a certain
condition is met, or timeout occurs. It can be used for the cases when a
timeout is required.

Signed-off-by: Adnan Rahman Chowdhury <adnan.chowdhury@sifive.com>
---
 include/sbi/sbi_timer.h |  3 +++
 lib/sbi/sbi_timer.c     | 18 ++++++++++++++++++
 2 files changed, 21 insertions(+)

Comments

Xiang W June 29, 2022, 2:57 p.m. UTC | #1
在 2022-06-29星期三的 14:42 +0100,Adnan Rahman Chowdhury写道:
> Motivation: Suppose a peripheral needs to be configured to transmit data.
> There is an SFR bit which indicates that the peripheral is ready to transmit.
> The firmware should check the bit and will only transmit data when the
> peripheral is ready. When the firmware starts polling the SFR, the peripheral
> could be busy transmitting/receiving other data so the firmware must wait
> till that completes. Assuming that there is no other way, the
> firmware shouldn't wait indefinitely.
> 
> The function sbi_timer_waitms_until() will constantly check whether a certain
> condition is met, or timeout occurs. It can be used for the cases when a
> timeout is required.
> 
> Signed-off-by: Adnan Rahman Chowdhury <adnan.chowdhury@sifive.com>
LGTM

Reviewed-by: Xiang W <wxjstz@126.com>
> ---
>  include/sbi/sbi_timer.h |  3 +++
>  lib/sbi/sbi_timer.c     | 18 ++++++++++++++++++
>  2 files changed, 21 insertions(+)
> 
> diff --git a/include/sbi/sbi_timer.h b/include/sbi/sbi_timer.h
> index 63ef1af..ea3dbdd 100644
> --- a/include/sbi/sbi_timer.h
> +++ b/include/sbi/sbi_timer.h
> @@ -48,6 +48,9 @@ static inline void sbi_timer_udelay(ulong usecs)
>         sbi_timer_delay_loop(usecs, 1000000, NULL, NULL);
>  }
>  
> +bool sbi_timer_waitms_until(bool (*predicate)(void *), void *arg,
> +                           uint64_t timeout_ms);
> +
>  /** Get timer value for current HART */
>  u64 sbi_timer_value(void);
>  
> diff --git a/lib/sbi/sbi_timer.c b/lib/sbi/sbi_timer.c
> index acdba92..d93036d 100644
> --- a/lib/sbi/sbi_timer.c
> +++ b/lib/sbi/sbi_timer.c
> @@ -81,6 +81,24 @@ void sbi_timer_delay_loop(ulong units, u64 unit_freq,
>                 delay_fn(opaque);
>  }
>  
> +bool sbi_timer_waitms_until(bool(*predicate)(void*), void* arg,
> +                           uint64_t timeout_ms)
> +{
> +       bool ret = true;
> +       uint64_t start_time = sbi_timer_value();
> +       uint64_t ticks =
> +               (sbi_timer_get_device()->timer_freq / 1000) *
> +               (timeout_ms);
> +       do {
> +               if (predicate(arg))
> +                       break;
> +               if (sbi_timer_value() - start_time  >= ticks)
> +                       ret = false;
> +       } while(ret);
> +
> +       return ret;
> +}
> +
>  u64 sbi_timer_value(void)
>  {
>         if (get_time_val)
> -- 
> 2.30.2
> 
>
Jessica Clarke June 29, 2022, 3:04 p.m. UTC | #2
On 29 Jun 2022, at 14:42, Adnan Rahman Chowdhury <adnan.chowdhury@sifive.com> wrote:
> 
> Motivation: Suppose a peripheral needs to be configured to transmit data.
> There is an SFR bit which indicates that the peripheral is ready to transmit.
> The firmware should check the bit and will only transmit data when the
> peripheral is ready. When the firmware starts polling the SFR, the peripheral
> could be busy transmitting/receiving other data so the firmware must wait
> till that completes. Assuming that there is no other way, the
> firmware shouldn't wait indefinitely.
> 
> The function sbi_timer_waitms_until() will constantly check whether a certain
> condition is met, or timeout occurs. It can be used for the cases when a
> timeout is required.
> 
> Signed-off-by: Adnan Rahman Chowdhury <adnan.chowdhury@sifive.com>
> ---
> include/sbi/sbi_timer.h |  3 +++
> lib/sbi/sbi_timer.c     | 18 ++++++++++++++++++
> 2 files changed, 21 insertions(+)
> 
> diff --git a/include/sbi/sbi_timer.h b/include/sbi/sbi_timer.h
> index 63ef1af..ea3dbdd 100644
> --- a/include/sbi/sbi_timer.h
> +++ b/include/sbi/sbi_timer.h
> @@ -48,6 +48,9 @@ static inline void sbi_timer_udelay(ulong usecs)
> 	sbi_timer_delay_loop(usecs, 1000000, NULL, NULL);
> }
> 
> +bool sbi_timer_waitms_until(bool (*predicate)(void *), void *arg,
> +			    uint64_t timeout_ms);
> +
> /** Get timer value for current HART */
> u64 sbi_timer_value(void);
> 
> diff --git a/lib/sbi/sbi_timer.c b/lib/sbi/sbi_timer.c
> index acdba92..d93036d 100644
> --- a/lib/sbi/sbi_timer.c
> +++ b/lib/sbi/sbi_timer.c
> @@ -81,6 +81,24 @@ void sbi_timer_delay_loop(ulong units, u64 unit_freq,
> 		delay_fn(opaque);
> }
> 
> +bool sbi_timer_waitms_until(bool(*predicate)(void*), void* arg,
> +			    uint64_t timeout_ms)

bool (*predicate)(void *) and void *arg

> +{
> +	bool ret = true;
> +	uint64_t start_time = sbi_timer_value();
> +	uint64_t ticks =
> +		(sbi_timer_get_device()->timer_freq / 1000) *
> +		(timeout_ms);

Parens around a variable?

> +	do {
> +		if (predicate(arg))
> +			break;
> +		if (sbi_timer_value() - start_time  >= ticks)

if (sbi_timer_value() - start_time >= ticks)

> +			ret = false;
> +	} while(ret);

while (ret)

Though this would be much more natural as:

while (!prediate(arg)) {
	if (sbi_timer_value() - start_time >= ticks)
		return false;
}

return true;

Or if you really want to avoid early return:

ret = true;
while (!prediate(arg)) {
	if (sbi_timer_value() - start_time >= ticks) {
		ret = false;
		break;
	}
}

return ret;

But I think early return is clearer here.

Jess

> +
> +	return ret;
> +}
> +
> u64 sbi_timer_value(void)
> {
> 	if (get_time_val)
> -- 
> 2.30.2
> 
> 
> -- 
> opensbi mailing list
> opensbi@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/opensbi
Adnan Rahman Chowdhury June 29, 2022, 3:30 p.m. UTC | #3
Thank you Xiang.

On Wed, Jun 29, 2022 at 3:58 PM Xiang W <wxjstz@126.com> wrote:
>
> 在 2022-06-29星期三的 14:42 +0100,Adnan Rahman Chowdhury写道:
> > Motivation: Suppose a peripheral needs to be configured to transmit data.
> > There is an SFR bit which indicates that the peripheral is ready to transmit.
> > The firmware should check the bit and will only transmit data when the
> > peripheral is ready. When the firmware starts polling the SFR, the peripheral
> > could be busy transmitting/receiving other data so the firmware must wait
> > till that completes. Assuming that there is no other way, the
> > firmware shouldn't wait indefinitely.
> >
> > The function sbi_timer_waitms_until() will constantly check whether a certain
> > condition is met, or timeout occurs. It can be used for the cases when a
> > timeout is required.
> >
> > Signed-off-by: Adnan Rahman Chowdhury <adnan.chowdhury@sifive.com>
> LGTM
>
> Reviewed-by: Xiang W <wxjstz@126.com>
> > ---
> >  include/sbi/sbi_timer.h |  3 +++
> >  lib/sbi/sbi_timer.c     | 18 ++++++++++++++++++
> >  2 files changed, 21 insertions(+)
> >
> > diff --git a/include/sbi/sbi_timer.h b/include/sbi/sbi_timer.h
> > index 63ef1af..ea3dbdd 100644
> > --- a/include/sbi/sbi_timer.h
> > +++ b/include/sbi/sbi_timer.h
> > @@ -48,6 +48,9 @@ static inline void sbi_timer_udelay(ulong usecs)
> >         sbi_timer_delay_loop(usecs, 1000000, NULL, NULL);
> >  }
> >
> > +bool sbi_timer_waitms_until(bool (*predicate)(void *), void *arg,
> > +                           uint64_t timeout_ms);
> > +
> >  /** Get timer value for current HART */
> >  u64 sbi_timer_value(void);
> >
> > diff --git a/lib/sbi/sbi_timer.c b/lib/sbi/sbi_timer.c
> > index acdba92..d93036d 100644
> > --- a/lib/sbi/sbi_timer.c
> > +++ b/lib/sbi/sbi_timer.c
> > @@ -81,6 +81,24 @@ void sbi_timer_delay_loop(ulong units, u64 unit_freq,
> >                 delay_fn(opaque);
> >  }
> >
> > +bool sbi_timer_waitms_until(bool(*predicate)(void*), void* arg,
> > +                           uint64_t timeout_ms)
> > +{
> > +       bool ret = true;
> > +       uint64_t start_time = sbi_timer_value();
> > +       uint64_t ticks =
> > +               (sbi_timer_get_device()->timer_freq / 1000) *
> > +               (timeout_ms);
> > +       do {
> > +               if (predicate(arg))
> > +                       break;
> > +               if (sbi_timer_value() - start_time  >= ticks)
> > +                       ret = false;
> > +       } while(ret);
> > +
> > +       return ret;
> > +}
> > +
> >  u64 sbi_timer_value(void)
> >  {
> >         if (get_time_val)
> > --
> > 2.30.2
> >
> >
>
>
Adnan Rahman Chowdhury June 29, 2022, 3:33 p.m. UTC | #4
On Wed, Jun 29, 2022 at 4:04 PM Jessica Clarke <jrtc27@jrtc27.com> wrote:
>
> On 29 Jun 2022, at 14:42, Adnan Rahman Chowdhury <adnan.chowdhury@sifive.com> wrote:
> >
> > Motivation: Suppose a peripheral needs to be configured to transmit data.
> > There is an SFR bit which indicates that the peripheral is ready to transmit.
> > The firmware should check the bit and will only transmit data when the
> > peripheral is ready. When the firmware starts polling the SFR, the peripheral
> > could be busy transmitting/receiving other data so the firmware must wait
> > till that completes. Assuming that there is no other way, the
> > firmware shouldn't wait indefinitely.
> >
> > The function sbi_timer_waitms_until() will constantly check whether a certain
> > condition is met, or timeout occurs. It can be used for the cases when a
> > timeout is required.
> >
> > Signed-off-by: Adnan Rahman Chowdhury <adnan.chowdhury@sifive.com>
> > ---
> > include/sbi/sbi_timer.h |  3 +++
> > lib/sbi/sbi_timer.c     | 18 ++++++++++++++++++
> > 2 files changed, 21 insertions(+)
> >
> > diff --git a/include/sbi/sbi_timer.h b/include/sbi/sbi_timer.h
> > index 63ef1af..ea3dbdd 100644
> > --- a/include/sbi/sbi_timer.h
> > +++ b/include/sbi/sbi_timer.h
> > @@ -48,6 +48,9 @@ static inline void sbi_timer_udelay(ulong usecs)
> >       sbi_timer_delay_loop(usecs, 1000000, NULL, NULL);
> > }
> >
> > +bool sbi_timer_waitms_until(bool (*predicate)(void *), void *arg,
> > +                         uint64_t timeout_ms);
> > +
> > /** Get timer value for current HART */
> > u64 sbi_timer_value(void);
> >
> > diff --git a/lib/sbi/sbi_timer.c b/lib/sbi/sbi_timer.c
> > index acdba92..d93036d 100644
> > --- a/lib/sbi/sbi_timer.c
> > +++ b/lib/sbi/sbi_timer.c
> > @@ -81,6 +81,24 @@ void sbi_timer_delay_loop(ulong units, u64 unit_freq,
> >               delay_fn(opaque);
> > }
> >
> > +bool sbi_timer_waitms_until(bool(*predicate)(void*), void* arg,
> > +                         uint64_t timeout_ms)
>
> bool (*predicate)(void *) and void *arg

Thanks for pointing this out.

>
> > +{
> > +     bool ret = true;
> > +     uint64_t start_time = sbi_timer_value();
> > +     uint64_t ticks =
> > +             (sbi_timer_get_device()->timer_freq / 1000) *
> > +             (timeout_ms);
>
> Parens around a variable?

This was actually a macro in the project I'm working on. Later I moved
it to be a function, looks suitable for sbi_timer. The parentheses came
from the macro. Will remove it.

>
> > +     do {
> > +             if (predicate(arg))
> > +                     break;
> > +             if (sbi_timer_value() - start_time  >= ticks)
>
> if (sbi_timer_value() - start_time >= ticks)
>
> > +                     ret = false;
> > +     } while(ret);
>
> while (ret)
>
> Though this would be much more natural as:
>
> while (!prediate(arg)) {
>         if (sbi_timer_value() - start_time >= ticks)
>                 return false;
> }
>
> return true;

This version is cleaner. Will update the patch. Thank you.

>
> Or if you really want to avoid early return:
>
> ret = true;
> while (!prediate(arg)) {
>         if (sbi_timer_value() - start_time >= ticks) {
>                 ret = false;
>                 break;
>         }
> }
>
> return ret;
>
> But I think early return is clearer here.
>
> Jess
>
> > +
> > +     return ret;
> > +}
> > +
> > u64 sbi_timer_value(void)
> > {
> >       if (get_time_val)
> > --
> > 2.30.2
> >
> >
> > --
> > opensbi mailing list
> > opensbi@lists.infradead.org
> > http://lists.infradead.org/mailman/listinfo/opensbi
>

--
Best Regards,
Adnan Rahman Chowdhury
diff mbox series

Patch

diff --git a/include/sbi/sbi_timer.h b/include/sbi/sbi_timer.h
index 63ef1af..ea3dbdd 100644
--- a/include/sbi/sbi_timer.h
+++ b/include/sbi/sbi_timer.h
@@ -48,6 +48,9 @@  static inline void sbi_timer_udelay(ulong usecs)
 	sbi_timer_delay_loop(usecs, 1000000, NULL, NULL);
 }
 
+bool sbi_timer_waitms_until(bool (*predicate)(void *), void *arg,
+			    uint64_t timeout_ms);
+
 /** Get timer value for current HART */
 u64 sbi_timer_value(void);
 
diff --git a/lib/sbi/sbi_timer.c b/lib/sbi/sbi_timer.c
index acdba92..d93036d 100644
--- a/lib/sbi/sbi_timer.c
+++ b/lib/sbi/sbi_timer.c
@@ -81,6 +81,24 @@  void sbi_timer_delay_loop(ulong units, u64 unit_freq,
 		delay_fn(opaque);
 }
 
+bool sbi_timer_waitms_until(bool(*predicate)(void*), void* arg,
+			    uint64_t timeout_ms)
+{
+	bool ret = true;
+	uint64_t start_time = sbi_timer_value();
+	uint64_t ticks =
+		(sbi_timer_get_device()->timer_freq / 1000) *
+		(timeout_ms);
+	do {
+		if (predicate(arg))
+			break;
+		if (sbi_timer_value() - start_time  >= ticks)
+			ret = false;
+	} while(ret);
+
+	return ret;
+}
+
 u64 sbi_timer_value(void)
 {
 	if (get_time_val)