Skip to content

Commit 008c4b3

Browse files
Rasmus Villemoesstroese
Rasmus Villemoes
authored andcommitted
cyclic: make clients embed a struct cyclic_info in their own data structure
There are of course not a whole lot of examples in-tree yet, but before they appear, let's make this API change: Instead of separately allocating a 'struct cyclic_info', make the users embed such an instance in their own structure, and make the convention that the callback simply receives the 'struct cyclic_info *', from which the clients can get their own data using the container_of() macro. This has a number of advantages. First, it means cyclic_register() simply cannot fail, simplifying the code. The necessary storage will simply be allocated automatically when the client's own structure is allocated (often via uclass_priv_auto or similar). Second, code for which CONFIG_CYCLIC is just an option can more easily be written without #ifdefs, if we just provide an empty struct cyclic_info {}. For example, the nested CONFIG_IS_ENABLED()s in https://lore.kernel.org/u-boot/[email protected]/ are mostly due to the existence of the 'struct cyclic_info *' member being guarded by #ifdef CONFIG_CYCLIC. And we do probably want to avoid the extra memory overhead of that member when !CONFIG_CYCLIC. But that is automatic if, instead of a 'struct cyclic_info *', one simply embeds a 'struct cyclic_info', which will have size 0 when !CONFIG_CYCLIC. Also, the no-op cyclic_register() function can just unconditionally be called, and the compiler will see that (1) the callback is referenced, so not emit a warning for a maybe-unused function and (2) see that it can actually never be reached, so not emit any code for it. Reviewed-by: Stefan Roese <[email protected]> Signed-off-by: Rasmus Villemoes <[email protected]>
1 parent df2b382 commit 008c4b3

File tree

7 files changed

+78
-80
lines changed

7 files changed

+78
-80
lines changed

board/Marvell/octeon_nic23/board.c

+7-4
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ void board_configure_qlms(void)
249249
* read the incorrect device ID 0x9700 (reset value) instead of 0x9702
250250
* (restored value).
251251
*/
252-
static void octeon_board_restore_pf(void *ctx)
252+
static void octeon_board_restore_pf(struct cyclic_info *c)
253253
{
254254
union cvmx_spemx_flr_pf_stopreq stopreq;
255255
static bool start_initialized[2] = {false, false};
@@ -357,10 +357,13 @@ int board_late_init(void)
357357
board_configure_qlms();
358358

359359
/* Register cyclic function for PCIe FLR fixup */
360-
cyclic = cyclic_register(octeon_board_restore_pf, 100,
361-
"pcie_flr_fix", NULL);
362-
if (!cyclic)
360+
cyclic = calloc(1, sizeof(*cyclic));
361+
if (cyclic) {
362+
cyclic_register(cyclic, octeon_board_restore_pf, 100,
363+
"pcie_flr_fix");
364+
} else {
363365
printf("Registering of cyclic function failed\n");
366+
}
364367

365368
return 0;
366369
}

cmd/cyclic.c

+5-7
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,16 @@
1515
#include <time.h>
1616
#include <vsprintf.h>
1717
#include <linux/delay.h>
18+
#include <linux/kernel.h>
1819

1920
struct cyclic_demo_info {
21+
struct cyclic_info cyclic;
2022
uint delay_us;
2123
};
2224

23-
static void cyclic_demo(void *ctx)
25+
static void cyclic_demo(struct cyclic_info *c)
2426
{
25-
struct cyclic_demo_info *info = ctx;
27+
struct cyclic_demo_info *info = container_of(c, struct cyclic_demo_info, cyclic);
2628

2729
/* Just a small dummy delay here */
2830
udelay(info->delay_us);
@@ -32,7 +34,6 @@ static int do_cyclic_demo(struct cmd_tbl *cmdtp, int flag, int argc,
3234
char *const argv[])
3335
{
3436
struct cyclic_demo_info *info;
35-
struct cyclic_info *cyclic;
3637
uint time_ms;
3738

3839
if (argc < 3)
@@ -48,10 +49,7 @@ static int do_cyclic_demo(struct cmd_tbl *cmdtp, int flag, int argc,
4849
info->delay_us = simple_strtoul(argv[2], NULL, 0);
4950

5051
/* Register demo cyclic function */
51-
cyclic = cyclic_register(cyclic_demo, time_ms * 1000, "cyclic_demo",
52-
info);
53-
if (!cyclic)
54-
printf("Registering of cyclic_demo failed\n");
52+
cyclic_register(&info->cyclic, cyclic_demo, time_ms * 1000, "cyclic_demo");
5553

5654
printf("Registered function \"%s\" to be executed all %dms\n",
5755
"cyclic_demo", time_ms);

common/cyclic.c

+5-17
Original file line numberDiff line numberDiff line change
@@ -26,34 +26,22 @@ struct hlist_head *cyclic_get_list(void)
2626
return (struct hlist_head *)&gd->cyclic_list;
2727
}
2828

29-
struct cyclic_info *cyclic_register(cyclic_func_t func, uint64_t delay_us,
30-
const char *name, void *ctx)
29+
void cyclic_register(struct cyclic_info *cyclic, cyclic_func_t func,
30+
uint64_t delay_us, const char *name)
3131
{
32-
struct cyclic_info *cyclic;
33-
34-
cyclic = calloc(1, sizeof(struct cyclic_info));
35-
if (!cyclic) {
36-
pr_debug("Memory allocation error\n");
37-
return NULL;
38-
}
32+
memset(cyclic, 0, sizeof(*cyclic));
3933

4034
/* Store values in struct */
4135
cyclic->func = func;
42-
cyclic->ctx = ctx;
4336
cyclic->name = name;
4437
cyclic->delay_us = delay_us;
4538
cyclic->start_time_us = timer_get_us();
4639
hlist_add_head(&cyclic->list, cyclic_get_list());
47-
48-
return cyclic;
4940
}
5041

51-
int cyclic_unregister(struct cyclic_info *cyclic)
42+
void cyclic_unregister(struct cyclic_info *cyclic)
5243
{
5344
hlist_del(&cyclic->list);
54-
free(cyclic);
55-
56-
return 0;
5745
}
5846

5947
void cyclic_run(void)
@@ -76,7 +64,7 @@ void cyclic_run(void)
7664
if (time_after_eq64(now, cyclic->next_call)) {
7765
/* Call cyclic function and account it's cpu-time */
7866
cyclic->next_call = now + cyclic->delay_us;
79-
cyclic->func(cyclic->ctx);
67+
cyclic->func(cyclic);
8068
cyclic->run_cnt++;
8169
cpu_time = timer_get_us() - now;
8270
cyclic->cpu_time_us += cpu_time;

doc/develop/cyclic.rst

+16-10
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,26 @@ Registering a cyclic function
1919

2020
To register a cyclic function, use something like this::
2121

22-
static void cyclic_demo(void *ctx)
22+
struct donkey {
23+
struct cyclic_info cyclic;
24+
void (*say)(const char *s);
25+
};
26+
27+
static void cyclic_demo(struct cyclic_info *c)
2328
{
24-
/* Just a small dummy delay here */
25-
udelay(10);
29+
struct donkey *donkey = container_of(c, struct donkey, cyclic);
30+
31+
donkey->say("Are we there yet?");
2632
}
27-
28-
int board_init(void)
33+
34+
int donkey_init(void)
2935
{
30-
struct cyclic_info *cyclic;
31-
36+
struct donkey *donkey;
37+
38+
/* Initialize donkey ... */
39+
3240
/* Register demo cyclic function */
33-
cyclic = cyclic_register(cyclic_demo, 10 * 1000, "cyclic_demo", NULL);
34-
if (!cyclic)
35-
printf("Registering of cyclic_demo failed\n");
41+
cyclic_register(&donkey->cyclic, cyclic_demo, 10 * 1000, "cyclic_demo");
3642
3743
return 0;
3844
}

drivers/watchdog/wdt-uclass.c

+15-18
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,15 @@
1717
#include <asm/global_data.h>
1818
#include <dm/device-internal.h>
1919
#include <dm/lists.h>
20+
#include <linux/kernel.h>
2021

2122
DECLARE_GLOBAL_DATA_PTR;
2223

2324
#define WATCHDOG_TIMEOUT_SECS (CONFIG_WATCHDOG_TIMEOUT_MSECS / 1000)
2425

2526
struct wdt_priv {
27+
/* The udevice owning this wdt_priv. */
28+
struct udevice *dev;
2629
/* Timeout, in seconds, to configure this device to. */
2730
u32 timeout;
2831
/*
@@ -40,18 +43,17 @@ struct wdt_priv {
4043
/* autostart */
4144
bool autostart;
4245

43-
struct cyclic_info *cyclic;
46+
struct cyclic_info cyclic;
4447
};
4548

46-
static void wdt_cyclic(void *ctx)
49+
static void wdt_cyclic(struct cyclic_info *c)
4750
{
48-
struct udevice *dev = ctx;
49-
struct wdt_priv *priv;
51+
struct wdt_priv *priv = container_of(c, struct wdt_priv, cyclic);
52+
struct udevice *dev = priv->dev;
5053

5154
if (!device_active(dev))
5255
return;
5356

54-
priv = dev_get_uclass_priv(dev);
5557
if (!priv->running)
5658
return;
5759

@@ -124,20 +126,14 @@ int wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
124126
memset(str, 0, 16);
125127
if (IS_ENABLED(CONFIG_WATCHDOG)) {
126128
if (priv->running)
127-
cyclic_unregister(priv->cyclic);
129+
cyclic_unregister(&priv->cyclic);
128130

129131
/* Register the watchdog driver as a cyclic function */
130-
priv->cyclic = cyclic_register(wdt_cyclic,
131-
priv->reset_period * 1000,
132-
dev->name, dev);
133-
if (!priv->cyclic) {
134-
printf("cyclic_register for %s failed\n",
135-
dev->name);
136-
return -ENODEV;
137-
} else {
138-
snprintf(str, 16, "every %ldms",
139-
priv->reset_period);
140-
}
132+
cyclic_register(&priv->cyclic, wdt_cyclic,
133+
priv->reset_period * 1000,
134+
dev->name);
135+
136+
snprintf(str, 16, "every %ldms", priv->reset_period);
141137
}
142138

143139
priv->running = true;
@@ -162,7 +158,7 @@ int wdt_stop(struct udevice *dev)
162158
struct wdt_priv *priv = dev_get_uclass_priv(dev);
163159

164160
if (IS_ENABLED(CONFIG_WATCHDOG) && priv->running)
165-
cyclic_unregister(priv->cyclic);
161+
cyclic_unregister(&priv->cyclic);
166162

167163
priv->running = false;
168164
}
@@ -262,6 +258,7 @@ static int wdt_pre_probe(struct udevice *dev)
262258
autostart = true;
263259
}
264260
priv = dev_get_uclass_priv(dev);
261+
priv->dev = dev;
265262
priv->timeout = timeout;
266263
priv->reset_period = reset_period;
267264
priv->autostart = autostart;

include/cyclic.h

+18-17
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
* struct cyclic_info - Information about cyclic execution function
1919
*
2020
* @func: Function to call periodically
21-
* @ctx: Context pointer to get passed to this function
2221
* @name: Name of the cyclic function, e.g. shown in the commands
2322
* @delay_ns: Delay is ns after which this function shall get executed
2423
* @start_time_us: Start time in us, when this function started its execution
@@ -27,10 +26,12 @@
2726
* @next_call: Next time in us, when the function shall be executed again
2827
* @list: List node
2928
* @already_warned: Flag that we've warned about exceeding CPU time usage
29+
*
30+
* When !CONFIG_CYCLIC, this struct is empty.
3031
*/
3132
struct cyclic_info {
32-
void (*func)(void *ctx);
33-
void *ctx;
33+
#if defined(CONFIG_CYCLIC)
34+
void (*func)(struct cyclic_info *c);
3435
const char *name;
3536
uint64_t delay_us;
3637
uint64_t start_time_us;
@@ -39,31 +40,34 @@ struct cyclic_info {
3940
uint64_t next_call;
4041
struct hlist_node list;
4142
bool already_warned;
43+
#endif
4244
};
4345

4446
/** Function type for cyclic functions */
45-
typedef void (*cyclic_func_t)(void *ctx);
47+
typedef void (*cyclic_func_t)(struct cyclic_info *c);
4648

4749
#if defined(CONFIG_CYCLIC)
4850
/**
4951
* cyclic_register - Register a new cyclic function
5052
*
53+
* @cyclic: Cyclic info structure
5154
* @func: Function to call periodically
5255
* @delay_us: Delay is us after which this function shall get executed
5356
* @name: Cyclic function name/id
54-
* @ctx: Context to pass to the function
55-
* @return: pointer to cyclic_struct if OK, NULL on error
57+
*
58+
* The function @func will be called with @cyclic as its
59+
* argument. @cyclic will usually be embedded in some device-specific
60+
* structure, which the callback can retrieve using container_of().
5661
*/
57-
struct cyclic_info *cyclic_register(cyclic_func_t func, uint64_t delay_us,
58-
const char *name, void *ctx);
62+
void cyclic_register(struct cyclic_info *cyclic, cyclic_func_t func,
63+
uint64_t delay_us, const char *name);
5964

6065
/**
6166
* cyclic_unregister - Unregister a cyclic function
6267
*
6368
* @cyclic: Pointer to cyclic_struct of the function that shall be removed
64-
* @return: 0 if OK, -ve on error
6569
*/
66-
int cyclic_unregister(struct cyclic_info *cyclic);
70+
void cyclic_unregister(struct cyclic_info *cyclic);
6771

6872
/**
6973
* cyclic_unregister_all() - Clean up cyclic functions
@@ -97,17 +101,14 @@ void cyclic_run(void);
97101
*/
98102
void schedule(void);
99103
#else
100-
static inline struct cyclic_info *cyclic_register(cyclic_func_t func,
101-
uint64_t delay_us,
102-
const char *name,
103-
void *ctx)
104+
105+
static inline void cyclic_register(struct cyclic_info *cyclic, cyclic_func_t func,
106+
uint64_t delay_us, const char *name)
104107
{
105-
return NULL;
106108
}
107109

108-
static inline int cyclic_unregister(struct cyclic_info *cyclic)
110+
static inline void cyclic_unregister(struct cyclic_info *cyclic)
109111
{
110-
return 0;
111112
}
112113

113114
static inline void cyclic_run(void)

test/common/cyclic.c

+12-7
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,27 @@
1212
#include <linux/delay.h>
1313

1414
/* Test that cyclic function is called */
15-
static bool cyclic_active = false;
15+
static struct cyclic_test {
16+
struct cyclic_info cyclic;
17+
bool called;
18+
} cyclic_test;
1619

17-
static void cyclic_test(void *ctx)
20+
static void test_cb(struct cyclic_info *c)
1821
{
19-
cyclic_active = true;
22+
struct cyclic_test *t = container_of(c, struct cyclic_test, cyclic);
23+
t->called = true;
2024
}
2125

2226
static int dm_test_cyclic_running(struct unit_test_state *uts)
2327
{
24-
cyclic_active = false;
25-
ut_assertnonnull(cyclic_register(cyclic_test, 10 * 1000, "cyclic_demo",
26-
NULL));
28+
cyclic_test.called = false;
29+
cyclic_register(&cyclic_test.cyclic, test_cb, 10 * 1000, "cyclic_test");
2730

2831
/* Execute all registered cyclic functions */
2932
schedule();
30-
ut_asserteq(true, cyclic_active);
33+
ut_asserteq(true, cyclic_test.called);
34+
35+
cyclic_unregister(&cyclic_test.cyclic);
3136

3237
return 0;
3338
}

0 commit comments

Comments
 (0)