- misc cyclic infrastructure improvements (Rasmus)
- watchdog_reset cleanup (Rasmus)

CI: https://dev.azure.com/sr0718/u-boot/_build/results?buildId=369&view=results
This commit is contained in:
Tom Rini 2024-06-16 09:10:13 -06:00
commit e242cd9513
15 changed files with 102 additions and 321 deletions

View File

@ -108,26 +108,6 @@ int do_reset(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
return 0;
};
#if defined(CONFIG_WATCHDOG)
void watchdog_reset(void)
{
mbar_writeShort(MCF_WTM_WSR, 0x5555);
mbar_writeShort(MCF_WTM_WSR, 0xAAAA);
}
int watchdog_disable(void)
{
mbar_writeShort(MCF_WTM_WCR, 0);
return (0);
}
int watchdog_init(void)
{
mbar_writeShort(MCF_WTM_WCR, MCF_WTM_WCR_EN);
return (0);
}
#endif /* #ifdef CONFIG_WATCHDOG */
#endif
#ifdef CONFIG_M5272
@ -174,49 +154,6 @@ int print_cpuinfo(void)
};
#endif /* CONFIG_DISPLAY_CPUINFO */
#if defined(CONFIG_WATCHDOG)
/* Called by macro WATCHDOG_RESET */
void watchdog_reset(void)
{
wdog_t *wdt = (wdog_t *)(MMAP_WDOG);
out_be16(&wdt->wdog_wcr, 0);
}
int watchdog_disable(void)
{
wdog_t *wdt = (wdog_t *)(MMAP_WDOG);
/* reset watchdog counter */
out_be16(&wdt->wdog_wcr, 0);
/* disable watchdog interrupt */
out_be16(&wdt->wdog_wirr, 0);
/* disable watchdog timer */
out_be16(&wdt->wdog_wrrr, 0);
puts("WATCHDOG:disabled\n");
return (0);
}
int watchdog_init(void)
{
wdog_t *wdt = (wdog_t *)(MMAP_WDOG);
/* disable watchdog interrupt */
out_be16(&wdt->wdog_wirr, 0);
/* set timeout and enable watchdog */
out_be16(&wdt->wdog_wrrr,
(CONFIG_WATCHDOG_TIMEOUT_MSECS * CONFIG_SYS_HZ) / (32768 * 1000) - 1);
/* reset watchdog counter */
out_be16(&wdt->wdog_wcr, 0);
puts("WATCHDOG:enabled\n");
return (0);
}
#endif /* #ifdef CONFIG_WATCHDOG */
#endif /* #ifdef CONFIG_M5272 */
#ifdef CONFIG_M5275
@ -243,51 +180,6 @@ int print_cpuinfo(void)
};
#endif /* CONFIG_DISPLAY_CPUINFO */
#if defined(CONFIG_WATCHDOG)
/* Called by macro WATCHDOG_RESET */
void watchdog_reset(void)
{
wdog_t *wdt = (wdog_t *)(MMAP_WDOG);
out_be16(&wdt->wsr, 0x5555);
out_be16(&wdt->wsr, 0xaaaa);
}
int watchdog_disable(void)
{
wdog_t *wdt = (wdog_t *)(MMAP_WDOG);
/* reset watchdog counter */
out_be16(&wdt->wsr, 0x5555);
out_be16(&wdt->wsr, 0xaaaa);
/* disable watchdog timer */
out_be16(&wdt->wcr, 0);
puts("WATCHDOG:disabled\n");
return (0);
}
int watchdog_init(void)
{
wdog_t *wdt = (wdog_t *)(MMAP_WDOG);
/* disable watchdog */
out_be16(&wdt->wcr, 0);
/* set timeout and enable watchdog */
out_be16(&wdt->wmr,
(CONFIG_WATCHDOG_TIMEOUT_MSECS * CONFIG_SYS_HZ) / (32768 * 1000) - 1);
/* reset watchdog counter */
out_be16(&wdt->wsr, 0x5555);
out_be16(&wdt->wsr, 0xaaaa);
puts("WATCHDOG:enabled\n");
return (0);
}
#endif /* #ifdef CONFIG_WATCHDOG */
#endif /* #ifdef CONFIG_M5275 */
#ifdef CONFIG_M5282

View File

@ -164,21 +164,6 @@ unsigned long get_tbclk(void)
}
#endif
#if defined(CONFIG_WATCHDOG) && !defined(CONFIG_WDT)
void watchdog_reset (void)
{
int re_enable = disable_interrupts();
/* Reset the 83xx watchdog */
volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
immr->wdt.swsrr = 0x556c;
immr->wdt.swsrr = 0xaa39;
if (re_enable)
enable_interrupts();
}
#endif
/*
* Initializes on-chip MMC controllers.
* to override, implement board_mmc_init()

View File

@ -349,37 +349,6 @@ __weak unsigned long get_tbclk(void)
}
#ifndef CONFIG_WDT
#if defined(CONFIG_WATCHDOG)
#define WATCHDOG_MASK (TCR_WP(63) | TCR_WRC(3) | TCR_WIE)
void
init_85xx_watchdog(void)
{
mtspr(SPRN_TCR, (mfspr(SPRN_TCR) & ~WATCHDOG_MASK) |
TCR_WP(CFG_WATCHDOG_PRESC) | TCR_WRC(CFG_WATCHDOG_RC));
}
void
reset_85xx_watchdog(void)
{
/*
* Clear TSR(WIS) bit by writing 1
*/
mtspr(SPRN_TSR, TSR_WIS);
}
void
watchdog_reset(void)
{
int re_enable = disable_interrupts();
reset_85xx_watchdog();
if (re_enable)
enable_interrupts();
}
#endif /* CONFIG_WATCHDOG */
#endif
/*
* Initializes on-chip MMC controllers.
* to override, implement board_mmc_init()

View File

@ -6,4 +6,4 @@
# (C) Copyright 2007
# Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
obj-y = cpu.o interrupts.o watchdog.o cache.o
obj-y = cpu.o interrupts.o cache.o

View File

@ -10,6 +10,16 @@
#include <net.h>
#include <netdev.h>
#include <asm/processor.h>
#include <asm/system.h>
void reset_cpu(void)
{
/* Address error with SR.BL=1 first. */
trigger_address_error();
while (1)
;
}
int checkcpu(void)
{

View File

@ -1,60 +0,0 @@
// SPDX-License-Identifier: GPL-2.0+
#include <cpu_func.h>
#include <asm/processor.h>
#include <asm/system.h>
#include <asm/io.h>
#define WDT_BASE WTCNT
#define WDT_WD (1 << 6)
#define WDT_RST_P (0)
#define WDT_RST_M (1 << 5)
#define WDT_ENABLE (1 << 7)
#if defined(CONFIG_WATCHDOG)
static unsigned char csr_read(void)
{
return inb(WDT_BASE + 0x04);
}
static void cnt_write(unsigned char value)
{
outl((unsigned short)value | 0x5A00, WDT_BASE + 0x00);
}
static void csr_write(unsigned char value)
{
outl((unsigned short)value | 0xA500, WDT_BASE + 0x04);
}
void watchdog_reset(void)
{
outl(0x55000000, WDT_BASE + 0x08);
}
int watchdog_init(void)
{
/* Set overflow time*/
cnt_write(0);
/* Power on reset */
csr_write(WDT_WD|WDT_RST_P|WDT_ENABLE);
return 0;
}
int watchdog_disable(void)
{
csr_write(csr_read() & ~WDT_ENABLE);
return 0;
}
#endif
void reset_cpu(void)
{
/* Address error with SR.BL=1 first. */
trigger_address_error();
while (1)
;
}

View File

@ -249,7 +249,7 @@ void board_configure_qlms(void)
* read the incorrect device ID 0x9700 (reset value) instead of 0x9702
* (restored value).
*/
static void octeon_board_restore_pf(void *ctx)
static void octeon_board_restore_pf(struct cyclic_info *c)
{
union cvmx_spemx_flr_pf_stopreq stopreq;
static bool start_initialized[2] = {false, false};
@ -357,10 +357,13 @@ int board_late_init(void)
board_configure_qlms();
/* Register cyclic function for PCIe FLR fixup */
cyclic = cyclic_register(octeon_board_restore_pf, 100,
"pcie_flr_fix", NULL);
if (!cyclic)
cyclic = calloc(1, sizeof(*cyclic));
if (cyclic) {
cyclic_register(cyclic, octeon_board_restore_pf, 100,
"pcie_flr_fix");
} else {
printf("Registering of cyclic function failed\n");
}
return 0;
}

View File

@ -15,14 +15,16 @@
#include <time.h>
#include <vsprintf.h>
#include <linux/delay.h>
#include <linux/kernel.h>
struct cyclic_demo_info {
struct cyclic_info cyclic;
uint delay_us;
};
static void cyclic_demo(void *ctx)
static void cyclic_demo(struct cyclic_info *c)
{
struct cyclic_demo_info *info = ctx;
struct cyclic_demo_info *info = container_of(c, struct cyclic_demo_info, cyclic);
/* Just a small dummy delay here */
udelay(info->delay_us);
@ -32,7 +34,6 @@ static int do_cyclic_demo(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
struct cyclic_demo_info *info;
struct cyclic_info *cyclic;
uint time_ms;
if (argc < 3)
@ -48,10 +49,7 @@ static int do_cyclic_demo(struct cmd_tbl *cmdtp, int flag, int argc,
info->delay_us = simple_strtoul(argv[2], NULL, 0);
/* Register demo cyclic function */
cyclic = cyclic_register(cyclic_demo, time_ms * 1000, "cyclic_demo",
info);
if (!cyclic)
printf("Registering of cyclic_demo failed\n");
cyclic_register(&info->cyclic, cyclic_demo, time_ms * 1000, "cyclic_demo");
printf("Registered function \"%s\" to be executed all %dms\n",
"cyclic_demo", time_ms);

View File

@ -26,34 +26,22 @@ struct hlist_head *cyclic_get_list(void)
return (struct hlist_head *)&gd->cyclic_list;
}
struct cyclic_info *cyclic_register(cyclic_func_t func, uint64_t delay_us,
const char *name, void *ctx)
void cyclic_register(struct cyclic_info *cyclic, cyclic_func_t func,
uint64_t delay_us, const char *name)
{
struct cyclic_info *cyclic;
cyclic = calloc(1, sizeof(struct cyclic_info));
if (!cyclic) {
pr_debug("Memory allocation error\n");
return NULL;
}
memset(cyclic, 0, sizeof(*cyclic));
/* Store values in struct */
cyclic->func = func;
cyclic->ctx = ctx;
cyclic->name = strdup(name);
cyclic->name = name;
cyclic->delay_us = delay_us;
cyclic->start_time_us = timer_get_us();
hlist_add_head(&cyclic->list, cyclic_get_list());
return cyclic;
}
int cyclic_unregister(struct cyclic_info *cyclic)
void cyclic_unregister(struct cyclic_info *cyclic)
{
hlist_del(&cyclic->list);
free(cyclic);
return 0;
}
void cyclic_run(void)
@ -76,7 +64,7 @@ void cyclic_run(void)
if (time_after_eq64(now, cyclic->next_call)) {
/* Call cyclic function and account it's cpu-time */
cyclic->next_call = now + cyclic->delay_us;
cyclic->func(cyclic->ctx);
cyclic->func(cyclic);
cyclic->run_cnt++;
cpu_time = timer_get_us() - now;
cyclic->cpu_time_us += cpu_time;

View File

@ -19,20 +19,26 @@ Registering a cyclic function
To register a cyclic function, use something like this::
static void cyclic_demo(void *ctx)
struct donkey {
struct cyclic_info cyclic;
void (*say)(const char *s);
};
static void cyclic_demo(struct cyclic_info *c)
{
/* Just a small dummy delay here */
udelay(10);
struct donkey *donkey = container_of(c, struct donkey, cyclic);
donkey->say("Are we there yet?");
}
int board_init(void)
int donkey_init(void)
{
struct cyclic_info *cyclic;
struct donkey *donkey;
/* Initialize donkey ... */
/* Register demo cyclic function */
cyclic = cyclic_register(cyclic_demo, 10 * 1000, "cyclic_demo", NULL);
if (!cyclic)
printf("Registering of cyclic_demo failed\n");
cyclic_register(&donkey->cyclic, cyclic_demo, 10 * 1000, "cyclic_demo");
return 0;
}

View File

@ -291,9 +291,9 @@ void ns16550_putc(struct ns16550 *com_port, char c)
serial_out(c, &com_port->thr);
/*
* Call watchdog_reset() upon newline. This is done here in putc
* Call schedule() upon newline. This is done here in putc
* since the environment code uses a single puts() to print the complete
* environment upon "printenv". So we can't put this watchdog call
* environment upon "printenv". So we can't put this schedule call
* in puts().
*/
if (c == '\n')
@ -390,9 +390,9 @@ static int ns16550_serial_putc(struct udevice *dev, const char ch)
serial_out(ch, &com_port->thr);
/*
* Call watchdog_reset() upon newline. This is done here in putc
* Call schedule() upon newline. This is done here in putc
* since the environment code uses a single puts() to print the complete
* environment upon "printenv". So we can't put this watchdog call
* environment upon "printenv". So we can't put this schedule call
* in puts().
*/
if (ch == '\n')

View File

@ -17,17 +17,20 @@
#include <asm/global_data.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <linux/kernel.h>
DECLARE_GLOBAL_DATA_PTR;
#define WATCHDOG_TIMEOUT_SECS (CONFIG_WATCHDOG_TIMEOUT_MSECS / 1000)
struct wdt_priv {
/* The udevice owning this wdt_priv. */
struct udevice *dev;
/* Timeout, in seconds, to configure this device to. */
u32 timeout;
/*
* Time, in milliseconds, between calling the device's ->reset()
* method from watchdog_reset().
* method from schedule().
*/
ulong reset_period;
/*
@ -40,18 +43,17 @@ struct wdt_priv {
/* autostart */
bool autostart;
struct cyclic_info *cyclic;
struct cyclic_info cyclic;
};
static void wdt_cyclic(void *ctx)
static void wdt_cyclic(struct cyclic_info *c)
{
struct udevice *dev = ctx;
struct wdt_priv *priv;
struct wdt_priv *priv = container_of(c, struct wdt_priv, cyclic);
struct udevice *dev = priv->dev;
if (!device_active(dev))
return;
priv = dev_get_uclass_priv(dev);
if (!priv->running)
return;
@ -121,24 +123,20 @@ int wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
struct wdt_priv *priv = dev_get_uclass_priv(dev);
char str[16];
priv->running = true;
memset(str, 0, 16);
if (IS_ENABLED(CONFIG_WATCHDOG)) {
if (priv->running)
cyclic_unregister(&priv->cyclic);
/* Register the watchdog driver as a cyclic function */
priv->cyclic = cyclic_register(wdt_cyclic,
priv->reset_period * 1000,
dev->name, dev);
if (!priv->cyclic) {
printf("cyclic_register for %s failed\n",
dev->name);
return -ENODEV;
} else {
snprintf(str, 16, "every %ldms",
priv->reset_period);
}
cyclic_register(&priv->cyclic, wdt_cyclic,
priv->reset_period * 1000,
dev->name);
snprintf(str, 16, "every %ldms", priv->reset_period);
}
priv->running = true;
printf("WDT: Started %s with%s servicing %s (%ds timeout)\n",
dev->name, IS_ENABLED(CONFIG_WATCHDOG) ? "" : "out",
str, (u32)lldiv(timeout_ms, 1000));
@ -159,6 +157,9 @@ int wdt_stop(struct udevice *dev)
if (ret == 0) {
struct wdt_priv *priv = dev_get_uclass_priv(dev);
if (IS_ENABLED(CONFIG_WATCHDOG) && priv->running)
cyclic_unregister(&priv->cyclic);
priv->running = false;
}
@ -221,21 +222,6 @@ int wdt_expire_now(struct udevice *dev, ulong flags)
return ret;
}
#if defined(CONFIG_WATCHDOG)
/*
* Called by macro WATCHDOG_RESET. This function be called *very* early,
* so we need to make sure, that the watchdog driver is ready before using
* it in this function.
*/
void watchdog_reset(void)
{
/*
* Empty function for now. The actual WDT handling is now done in
* the cyclic function instead.
*/
}
#endif
static int wdt_pre_probe(struct udevice *dev)
{
u32 timeout = WATCHDOG_TIMEOUT_SECS;
@ -257,12 +243,13 @@ static int wdt_pre_probe(struct udevice *dev)
autostart = true;
}
priv = dev_get_uclass_priv(dev);
priv->dev = dev;
priv->timeout = timeout;
priv->reset_period = reset_period;
priv->autostart = autostart;
/*
* Pretend this device was last reset "long" ago so the first
* watchdog_reset will actually call its ->reset method.
* schedule() will actually call its ->reset method.
*/
priv->next_reset = get_timer(0);

View File

@ -18,7 +18,6 @@
* struct cyclic_info - Information about cyclic execution function
*
* @func: Function to call periodically
* @ctx: Context pointer to get passed to this function
* @name: Name of the cyclic function, e.g. shown in the commands
* @delay_ns: Delay is ns after which this function shall get executed
* @start_time_us: Start time in us, when this function started its execution
@ -27,11 +26,13 @@
* @next_call: Next time in us, when the function shall be executed again
* @list: List node
* @already_warned: Flag that we've warned about exceeding CPU time usage
*
* When !CONFIG_CYCLIC, this struct is empty.
*/
struct cyclic_info {
void (*func)(void *ctx);
void *ctx;
char *name;
#if defined(CONFIG_CYCLIC)
void (*func)(struct cyclic_info *c);
const char *name;
uint64_t delay_us;
uint64_t start_time_us;
uint64_t cpu_time_us;
@ -39,31 +40,34 @@ struct cyclic_info {
uint64_t next_call;
struct hlist_node list;
bool already_warned;
#endif
};
/** Function type for cyclic functions */
typedef void (*cyclic_func_t)(void *ctx);
typedef void (*cyclic_func_t)(struct cyclic_info *c);
#if defined(CONFIG_CYCLIC)
/**
* cyclic_register - Register a new cyclic function
*
* @cyclic: Cyclic info structure
* @func: Function to call periodically
* @delay_us: Delay is us after which this function shall get executed
* @name: Cyclic function name/id
* @ctx: Context to pass to the function
* @return: pointer to cyclic_struct if OK, NULL on error
*
* 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().
*/
struct cyclic_info *cyclic_register(cyclic_func_t func, uint64_t delay_us,
const char *name, void *ctx);
void cyclic_register(struct cyclic_info *cyclic, cyclic_func_t func,
uint64_t delay_us, const char *name);
/**
* cyclic_unregister - Unregister a cyclic function
*
* @cyclic: Pointer to cyclic_struct of the function that shall be removed
* @return: 0 if OK, -ve on error
*/
int cyclic_unregister(struct cyclic_info *cyclic);
void cyclic_unregister(struct cyclic_info *cyclic);
/**
* cyclic_unregister_all() - Clean up cyclic functions
@ -97,17 +101,14 @@ void cyclic_run(void);
*/
void schedule(void);
#else
static inline struct cyclic_info *cyclic_register(cyclic_func_t func,
uint64_t delay_us,
const char *name,
void *ctx)
static inline void cyclic_register(struct cyclic_info *cyclic, cyclic_func_t func,
uint64_t delay_us, const char *name)
{
return NULL;
}
static inline int cyclic_unregister(struct cyclic_info *cyclic)
static inline void cyclic_unregister(struct cyclic_info *cyclic)
{
return 0;
}
static inline void cyclic_run(void)

View File

@ -40,7 +40,4 @@ int init_func_watchdog_reset(void);
void hw_watchdog_init(void);
#endif
#if defined(CONFIG_MPC85xx)
void init_85xx_watchdog(void);
#endif
#endif /* _WATCHDOG_H_ */

View File

@ -12,22 +12,27 @@
#include <linux/delay.h>
/* Test that cyclic function is called */
static bool cyclic_active = false;
static struct cyclic_test {
struct cyclic_info cyclic;
bool called;
} cyclic_test;
static void cyclic_test(void *ctx)
static void test_cb(struct cyclic_info *c)
{
cyclic_active = true;
struct cyclic_test *t = container_of(c, struct cyclic_test, cyclic);
t->called = true;
}
static int dm_test_cyclic_running(struct unit_test_state *uts)
{
cyclic_active = false;
ut_assertnonnull(cyclic_register(cyclic_test, 10 * 1000, "cyclic_demo",
NULL));
cyclic_test.called = false;
cyclic_register(&cyclic_test.cyclic, test_cb, 10 * 1000, "cyclic_test");
/* Execute all registered cyclic functions */
schedule();
ut_asserteq(true, cyclic_active);
ut_asserteq(true, cyclic_test.called);
cyclic_unregister(&cyclic_test.cyclic);
return 0;
}