[U-Boot] [PATCH v2 0/5] Introduce basic headers for time, typecheck, iopoll

Changes in v2: - Fix typo include/timer.h -> include/time.h
Masahiro Yamada (5): delay: collect {m,n,u}delay declarations to include/linux/delay.h time: move timer APIs to include/time.h typecheck: import include/linux/typecheck.h from Linux 4.9 time: import time_after, time_before and friends from Linux iopoll: import include/linux/iopoll.h from Linux 4.9
include/common.h | 14 ++-------- include/linux/compat.h | 2 -- include/linux/delay.h | 24 +++++++++++++++++ include/linux/iopoll.h | 68 +++++++++++++++++++++++++++++++++++++++++++++++ include/linux/typecheck.h | 24 +++++++++++++++++ include/time.h | 57 +++++++++++++++++++++++++++++++++++++++ lib/time.c | 6 ----- 7 files changed, 175 insertions(+), 20 deletions(-) create mode 100644 include/linux/delay.h create mode 100644 include/linux/iopoll.h create mode 100644 include/linux/typecheck.h create mode 100644 include/time.h

Currently, mdelay() and udelay() are declared in include/common.h, while ndelay() in include/linux/compat.h. It would be nice to collect them into include/linux/delay.h like Linux.
While we are here, fix the ndelay() implementation; I used the DIV_ROUND_UP() instead of (x)/1000 because it must wait *longer* than the given period of time.
Signed-off-by: Masahiro Yamada yamada.masahiro@socionext.com Reviewed-by: Simon Glass sjg@chromium.org ---
Changes in v2: None
include/common.h | 6 +----- include/linux/compat.h | 2 -- include/linux/delay.h | 24 ++++++++++++++++++++++++ lib/time.c | 6 ------ 4 files changed, 25 insertions(+), 13 deletions(-) create mode 100644 include/linux/delay.h
diff --git a/include/common.h b/include/common.h index a8d833b..682205d 100644 --- a/include/common.h +++ b/include/common.h @@ -19,6 +19,7 @@ typedef volatile unsigned char vu_char; #include <errno.h> #include <asm-offsets.h> #include <linux/bitops.h> +#include <linux/delay.h> #include <linux/types.h> #include <linux/string.h> #include <linux/stringify.h> @@ -776,7 +777,6 @@ uint64_t get_ticks(void); void wait_ticks (unsigned long);
/* arch/$(ARCH)/lib/time.c */ -void __udelay (unsigned long); ulong usec2ticks (unsigned long usec); ulong ticks2usec (unsigned long ticks); int init_timebase (void); @@ -833,10 +833,6 @@ void qsort(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *)); int strcmp_compar(const void *, const void *);
-/* lib/time.c */ -void udelay (unsigned long); -void mdelay(unsigned long); - /* lib/uuid.c */ #include <uuid.h>
diff --git a/include/linux/compat.h b/include/linux/compat.h index 533983f..a43e4d6 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -15,8 +15,6 @@ struct p_current{
extern struct p_current *current;
-#define ndelay(x) udelay((x) < 1000 ? 1 : (x)/1000) - #define dev_dbg(dev, fmt, args...) \ debug(fmt, ##args) #define dev_vdbg(dev, fmt, args...) \ diff --git a/include/linux/delay.h b/include/linux/delay.h new file mode 100644 index 0000000..3dcd435 --- /dev/null +++ b/include/linux/delay.h @@ -0,0 +1,24 @@ +/* + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _LINUX_DELAY_H +#define _LINUX_DELAY_H + +#include <linux/kernel.h> + +void __udelay(unsigned long usec); +void udelay(unsigned long usec); + +static inline void mdelay(unsigned long msec) +{ + while (msec--) + udelay(1000); +} + +static inline void ndelay(unsigned long nsec) +{ + udelay(DIV_ROUND_UP(nsec, 1000)); +} + +#endif /* defined(_LINUX_DELAY_H) */ diff --git a/lib/time.c b/lib/time.c index f37150f..3c49243 100644 --- a/lib/time.c +++ b/lib/time.c @@ -154,9 +154,3 @@ void udelay(unsigned long usec) usec -= kv; } while(usec); } - -void mdelay(unsigned long msec) -{ - while (msec--) - udelay(1000); -}

On Wed, Dec 28, 2016 at 12:35:59AM +0900, Masahiro Yamada wrote:
Currently, mdelay() and udelay() are declared in include/common.h, while ndelay() in include/linux/compat.h. It would be nice to collect them into include/linux/delay.h like Linux.
While we are here, fix the ndelay() implementation; I used the DIV_ROUND_UP() instead of (x)/1000 because it must wait *longer* than the given period of time.
Signed-off-by: Masahiro Yamada yamada.masahiro@socionext.com Reviewed-by: Simon Glass sjg@chromium.org
Applied to u-boot/master, thanks!

The include/common.h is a collection of unrelated declarations, macros, etc.
It is horrible to include such a cluttered header just for some timer functions. Split out timer functions into include/time.h.
Signed-off-by: Masahiro Yamada yamada.masahiro@socionext.com Reviewed-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Fix typo include/timer.h -> include/time.h
include/common.h | 8 +------- include/time.h | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 7 deletions(-) create mode 100644 include/time.h
diff --git a/include/common.h b/include/common.h index 682205d..08f581c 100644 --- a/include/common.h +++ b/include/common.h @@ -17,6 +17,7 @@ typedef volatile unsigned char vu_char;
#include <config.h> #include <errno.h> +#include <time.h> #include <asm-offsets.h> #include <linux/bitops.h> #include <linux/delay.h> @@ -577,12 +578,6 @@ void ddr_enable_ecc(unsigned int dram_size); #endif #endif
-/* - * Return the current value of a monotonically increasing microsecond timer. - * Granularity may be larger than 1us if hardware does not support this. - */ -ulong timer_get_us(void); - /* $(CPU)/cpu.c */ static inline int cpumask_next(int cpu, unsigned int mask) { @@ -721,7 +716,6 @@ void external_interrupt (struct pt_regs *); void irq_install_handler(int, interrupt_handler_t *, void *); void irq_free_handler (int); void reset_timer (void); -ulong get_timer (ulong base);
/* Return value of monotonic microsecond timer */ unsigned long timer_get_us(void); diff --git a/include/time.h b/include/time.h new file mode 100644 index 0000000..5ed021f --- /dev/null +++ b/include/time.h @@ -0,0 +1,16 @@ +/* + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _TIME_H +#define _TIME_H + +unsigned long get_timer(unsigned long base); + +/* + * Return the current value of a monotonically increasing microsecond timer. + * Granularity may be larger than 1us if hardware does not support this. + */ +unsigned long timer_get_us(void); + +#endif /* _TIME_H */

On Wed, Dec 28, 2016 at 12:36:00AM +0900, Masahiro Yamada wrote:
The include/common.h is a collection of unrelated declarations, macros, etc.
It is horrible to include such a cluttered header just for some timer functions. Split out timer functions into include/time.h.
Signed-off-by: Masahiro Yamada yamada.masahiro@socionext.com Reviewed-by: Simon Glass sjg@chromium.org
Applied to u-boot/master, thanks!

Copied from Linux 4.9.
Signed-off-by: Masahiro Yamada yamada.masahiro@socionext.com ---
Changes in v2: None
include/linux/typecheck.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 include/linux/typecheck.h
diff --git a/include/linux/typecheck.h b/include/linux/typecheck.h new file mode 100644 index 0000000..eb5b74a --- /dev/null +++ b/include/linux/typecheck.h @@ -0,0 +1,24 @@ +#ifndef TYPECHECK_H_INCLUDED +#define TYPECHECK_H_INCLUDED + +/* + * Check at compile time that something is of a particular type. + * Always evaluates to 1 so you may use it easily in comparisons. + */ +#define typecheck(type,x) \ +({ type __dummy; \ + typeof(x) __dummy2; \ + (void)(&__dummy == &__dummy2); \ + 1; \ +}) + +/* + * Check at compile time that 'function' is a certain type, or is a pointer + * to that type (needs to use typedef for the function type.) + */ +#define typecheck_fn(type,function) \ +({ typeof(type) __tmp = function; \ + (void)__tmp; \ +}) + +#endif /* TYPECHECK_H_INCLUDED */

On Wed, Dec 28, 2016 at 12:36:01AM +0900, Masahiro Yamada wrote:
Copied from Linux 4.9.
Signed-off-by: Masahiro Yamada yamada.masahiro@socionext.com
Applied to u-boot/master, thanks!

It is not safe to compare timer values directly.
On 32-bit systems, for example, timer_get_us() wraps around every 72 min. (2 ^ 32 / 1000000 =~ 4295 sec =~ 72 min). Depending on the get_ticks() implementation, it may wrap more frequently. The 72 min might be possible on the use of U-Boot.
Let's borrow time_after, time_before, and friends to solve the wrap-around problem.
These macros were copied from include/linux/jiffies.h of Linux 4.9.
Signed-off-by: Masahiro Yamada yamada.masahiro@socionext.com ---
Changes in v2: None
include/time.h | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+)
diff --git a/include/time.h b/include/time.h index 5ed021f..5746ad9 100644 --- a/include/time.h +++ b/include/time.h @@ -5,6 +5,8 @@ #ifndef _TIME_H #define _TIME_H
+#include <linux/typecheck.h> + unsigned long get_timer(unsigned long base);
/* @@ -13,4 +15,43 @@ unsigned long get_timer(unsigned long base); */ unsigned long timer_get_us(void);
+/* + * These inlines deal with timer wrapping correctly. You are + * strongly encouraged to use them + * 1. Because people otherwise forget + * 2. Because if the timer wrap changes in future you won't have to + * alter your driver code. + * + * time_after(a,b) returns true if the time a is after time b. + * + * Do this with "<0" and ">=0" to only test the sign of the result. A + * good compiler would generate better code (and a really good compiler + * wouldn't care). Gcc is currently neither. + */ +#define time_after(a,b) \ + (typecheck(unsigned long, a) && \ + typecheck(unsigned long, b) && \ + ((long)((b) - (a)) < 0)) +#define time_before(a,b) time_after(b,a) + +#define time_after_eq(a,b) \ + (typecheck(unsigned long, a) && \ + typecheck(unsigned long, b) && \ + ((long)((a) - (b)) >= 0)) +#define time_before_eq(a,b) time_after_eq(b,a) + +/* + * Calculate whether a is in the range of [b, c]. + */ +#define time_in_range(a,b,c) \ + (time_after_eq(a,b) && \ + time_before_eq(a,c)) + +/* + * Calculate whether a is in the range of [b, c). + */ +#define time_in_range_open(a,b,c) \ + (time_after_eq(a,b) && \ + time_before(a,c)) + #endif /* _TIME_H */

On 27 December 2016 at 08:36, Masahiro Yamada yamada.masahiro@socionext.com wrote:
It is not safe to compare timer values directly.
On 32-bit systems, for example, timer_get_us() wraps around every 72 min. (2 ^ 32 / 1000000 =~ 4295 sec =~ 72 min). Depending on the get_ticks() implementation, it may wrap more frequently. The 72 min might be possible on the use of U-Boot.
Let's borrow time_after, time_before, and friends to solve the wrap-around problem.
These macros were copied from include/linux/jiffies.h of Linux 4.9.
Signed-off-by: Masahiro Yamada yamada.masahiro@socionext.com
Changes in v2: None
include/time.h | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org

On Wed, Dec 28, 2016 at 12:36:02AM +0900, Masahiro Yamada wrote:
It is not safe to compare timer values directly.
On 32-bit systems, for example, timer_get_us() wraps around every 72 min. (2 ^ 32 / 1000000 =~ 4295 sec =~ 72 min). Depending on the get_ticks() implementation, it may wrap more frequently. The 72 min might be possible on the use of U-Boot.
Let's borrow time_after, time_before, and friends to solve the wrap-around problem.
These macros were copied from include/linux/jiffies.h of Linux 4.9.
Signed-off-by: Masahiro Yamada yamada.masahiro@socionext.com Reviewed-by: Simon Glass sjg@chromium.org
Applied to u-boot/master, thanks!

This was imported from Linux 4.9 and adjusted for U-Boot.
- Replace the license block with SPDX - Drop all *_atomic variants, which make no sense for U-Boot - Remove the sleep_us argument, which makes no sense for U-Boot
Signed-off-by: Masahiro Yamada yamada.masahiro@socionext.com ---
Changes in v2: None
include/linux/iopoll.h | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 include/linux/iopoll.h
diff --git a/include/linux/iopoll.h b/include/linux/iopoll.h new file mode 100644 index 0000000..31c55ae --- /dev/null +++ b/include/linux/iopoll.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _LINUX_IOPOLL_H +#define _LINUX_IOPOLL_H + +#include <linux/errno.h> +#include <linux/io.h> +#include <time.h> + +/** + * readx_poll_timeout - Periodically poll an address until a condition is met or a timeout occurs + * @op: accessor function (takes @addr as its only argument) + * @addr: Address to poll + * @val: Variable to read the value into + * @cond: Break condition (usually involving @val) + * @timeout_us: Timeout in us, 0 means never timeout + * + * Returns 0 on success and -ETIMEDOUT upon a timeout. In either + * case, the last read value at @addr is stored in @val. + * + * When available, you'll probably want to use one of the specialized + * macros defined below rather than this macro directly. + */ +#define readx_poll_timeout(op, addr, val, cond, timeout_us) \ +({ \ + unsigned long timeout = timer_get_us() + timeout_us; \ + for (;;) { \ + (val) = op(addr); \ + if (cond) \ + break; \ + if (timeout_us && time_after(timer_get_us(), timeout)) { \ + (val) = op(addr); \ + break; \ + } \ + } \ + (cond) ? 0 : -ETIMEDOUT; \ +}) + + +#define readb_poll_timeout(addr, val, cond, timeout_us) \ + readx_poll_timeout(readb, addr, val, cond, timeout_us) + +#define readw_poll_timeout(addr, val, cond, timeout_us) \ + readx_poll_timeout(readw, addr, val, cond, timeout_us) + +#define readl_poll_timeout(addr, val, cond, timeout_us) \ + readx_poll_timeout(readl, addr, val, cond, timeout_us) + +#define readq_poll_timeout(addr, val, cond, timeout_us) \ + readx_poll_timeout(readq, addr, val, cond, timeout_us) + +#define readb_relaxed_poll_timeout(addr, val, cond, timeout_us) \ + readx_poll_timeout(readb_relaxed, addr, val, cond, timeout_us) + +#define readw_relaxed_poll_timeout(addr, val, cond, timeout_us) \ + readx_poll_timeout(readw_relaxed, addr, val, cond, timeout_us) + +#define readl_relaxed_poll_timeout(addr, val, cond, timeout_us) \ + readx_poll_timeout(readl_relaxed, addr, val, cond, timeout_us) + +#define readq_relaxed_poll_timeout(addr, val, cond, timeout_us) \ + readx_poll_timeout(readq_relaxed, addr, val, cond, timeout_us) + +#endif /* _LINUX_IOPOLL_H */

On Wed, Dec 28, 2016 at 12:36:03AM +0900, Masahiro Yamada wrote:
This was imported from Linux 4.9 and adjusted for U-Boot.
- Replace the license block with SPDX
- Drop all *_atomic variants, which make no sense for U-Boot
- Remove the sleep_us argument, which makes no sense for U-Boot
Signed-off-by: Masahiro Yamada yamada.masahiro@socionext.com
Applied to u-boot/master, thanks!
participants (3)
-
Masahiro Yamada
-
Simon Glass
-
Tom Rini