Make cyclic_register() return error code, 0 in case of success,
-EALREADY in case the called attempts to re-register already
registered struct cyclic_info. The re-registration would lead
to corruption of gd->cyclic_list because the re-registration
would memset() one of its nodes, prevent that. Unregister only
initialized struct cyclic_info.

Signed-off-by: Marek Vasut <[email protected]>
---
Cc: Aaron Williams <[email protected]>
Cc: Anatolij Gustschin <[email protected]>
Cc: Angelo Dureghello <[email protected]>
Cc: Christian Marangi <[email protected]>
Cc: Devarsh Thakkar <[email protected]>
Cc: Heinrich Schuchardt <[email protected]>
Cc: Jaehoon Chung <[email protected]>
Cc: Michael Polyntsov <[email protected]>
Cc: Michael Trimarchi <[email protected]>
Cc: Nikhil M Jain <[email protected]>
Cc: Peng Fan <[email protected]>
Cc: Peter Robinson <[email protected]>
Cc: Rasmus Villemoes <[email protected]>
Cc: Ronald Wahl <[email protected]>
Cc: Simon Glass <[email protected]>
Cc: Stefan Roese <[email protected]>
Cc: Tim Harvey <[email protected]>
Cc: Tom Rini <[email protected]>
Cc: [email protected]
---
 common/cyclic.c  | 14 +++++++++++---
 include/cyclic.h |  9 ++++++---
 2 files changed, 17 insertions(+), 6 deletions(-)

diff --git a/common/cyclic.c b/common/cyclic.c
index 196797fd61e..53156a704cc 100644
--- a/common/cyclic.c
+++ b/common/cyclic.c
@@ -27,9 +27,13 @@ struct hlist_head *cyclic_get_list(void)
        return (struct hlist_head *)&gd->cyclic_list;
 }
 
-void cyclic_register(struct cyclic_info *cyclic, cyclic_func_t func,
-                    uint64_t delay_us, const char *name)
+int cyclic_register(struct cyclic_info *cyclic, cyclic_func_t func,
+                   uint64_t delay_us, const char *name)
 {
+       /* Reassignment of function would corrupt cyclic list, exit */
+       if (cyclic->func)
+               return -EALREADY;
+
        memset(cyclic, 0, sizeof(*cyclic));
 
        /* Store values in struct */
@@ -38,11 +42,15 @@ void cyclic_register(struct cyclic_info *cyclic, 
cyclic_func_t func,
        cyclic->delay_us = delay_us;
        cyclic->start_time_us = timer_get_us();
        hlist_add_head(&cyclic->list, cyclic_get_list());
+
+       return 0;
 }
 
 void cyclic_unregister(struct cyclic_info *cyclic)
 {
-       hlist_del(&cyclic->list);
+       /* Unregister only initialized struct cyclic_info */
+       if (cyclic->func)
+               hlist_del(&cyclic->list);
 }
 
 static void cyclic_run(void)
diff --git a/include/cyclic.h b/include/cyclic.h
index c6c463d68e9..c86ac407332 100644
--- a/include/cyclic.h
+++ b/include/cyclic.h
@@ -60,8 +60,10 @@ typedef void (*cyclic_func_t)(struct cyclic_info *c);
  * The function @func will be called with @cyclic as its
  * argument. @cyclic will usually be embedded in some device-specific
  * structure, which the callback can retrieve using container_of().
+ *
+ * @return 0 on success, -EALREADY on repeated registration, -ve otherwise
  */
-void cyclic_register(struct cyclic_info *cyclic, cyclic_func_t func,
+int cyclic_register(struct cyclic_info *cyclic, cyclic_func_t func,
                     uint64_t delay_us, const char *name);
 
 /**
@@ -89,9 +91,10 @@ struct hlist_head *cyclic_get_list(void);
 
 #else
 
-static inline void cyclic_register(struct cyclic_info *cyclic, cyclic_func_t 
func,
-                                  uint64_t delay_us, const char *name)
+static inline int cyclic_register(struct cyclic_info *cyclic, cyclic_func_t 
func,
+                                 uint64_t delay_us, const char *name)
 {
+       return 0;
 }
 
 static inline void cyclic_unregister(struct cyclic_info *cyclic)
-- 
2.45.2

Reply via email to