mirror of
https://github.com/apache/nuttx.git
synced 2026-08-01 20:28:58 +00:00
drivers/watchdog: fix capture automonitor notifier context
Provide per-instance capture automonitor lookup for watchdog lower halves that pass callback context, and avoid selecting an unrelated watchdog when legacy lower halves provide no context. Update STM32 WWDG lower halves to pass their instance context so multiple watchdog devices remain distinguishable. Signed-off-by: hanzhijian <hanzhijian@zepp.com> Assisted-by: OpenAI Codex
This commit is contained in:
parent
20c280724a
commit
2bf7d987ed
6 changed files with 206 additions and 10 deletions
|
|
@ -299,7 +299,7 @@ static int stm32_interrupt(int irq, void *context, void *arg)
|
|||
* upon return.
|
||||
*/
|
||||
|
||||
priv->handler(irq, context, arg);
|
||||
priv->handler(irq, context, priv);
|
||||
}
|
||||
|
||||
/* The EWI interrupt is cleared by writing '0' to the EWIF bit in the
|
||||
|
|
|
|||
|
|
@ -299,7 +299,7 @@ static int stm32_interrupt(int irq, void *context, void *arg)
|
|||
* upon return.
|
||||
*/
|
||||
|
||||
priv->handler(irq, context, arg);
|
||||
priv->handler(irq, context, priv);
|
||||
}
|
||||
|
||||
/* The EWI interrupt is cleared by writing '0' to the EWIF bit in the
|
||||
|
|
|
|||
|
|
@ -298,7 +298,7 @@ static int stm32_interrupt(int irq, void *context, void *arg)
|
|||
* upon return.
|
||||
*/
|
||||
|
||||
priv->handler(irq, context, arg);
|
||||
priv->handler(irq, context, priv);
|
||||
}
|
||||
|
||||
/* The EWI interrupt is cleared by writing '0' to the EWIF bit in the
|
||||
|
|
|
|||
77
boards/sim/sim/sim/configs/watchdog-notifier/defconfig
Normal file
77
boards/sim/sim/sim/configs/watchdog-notifier/defconfig
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
#
|
||||
# This file is autogenerated: PLEASE DO NOT EDIT IT.
|
||||
#
|
||||
# You can use "make menuconfig" to make any modifications to the installed .config file.
|
||||
# You can then do "make savedefconfig" to generate a new defconfig file that includes your
|
||||
# modifications.
|
||||
#
|
||||
# CONFIG_NSH_CMDOPT_HEXDUMP is not set
|
||||
CONFIG_ALLOW_MIT_COMPONENTS=y
|
||||
CONFIG_ARCH="sim"
|
||||
CONFIG_ARCH_BOARD="sim"
|
||||
CONFIG_ARCH_BOARD_SIM=y
|
||||
CONFIG_ARCH_CHIP="sim"
|
||||
CONFIG_ARCH_SIM=y
|
||||
CONFIG_BOARDCTL_APP_SYMTAB=y
|
||||
CONFIG_BOARDCTL_POWEROFF=y
|
||||
CONFIG_BOARD_LOOPSPERMSEC=0
|
||||
CONFIG_BOOT_RUNFROMEXTSRAM=y
|
||||
CONFIG_BUILTIN=y
|
||||
CONFIG_DEBUG_ASSERTIONS=y
|
||||
CONFIG_DEBUG_ASSERTIONS_EXPRESSION=y
|
||||
CONFIG_DEBUG_FEATURES=y
|
||||
CONFIG_DEBUG_SYMBOLS=y
|
||||
CONFIG_DEV_GPIO=y
|
||||
CONFIG_DEV_LOOP=y
|
||||
CONFIG_ETC_FATDEVNO=2
|
||||
CONFIG_ETC_ROMFS=y
|
||||
CONFIG_ETC_ROMFSDEVNO=1
|
||||
CONFIG_FAT_LCNAMES=y
|
||||
CONFIG_FAT_LFN=y
|
||||
CONFIG_FS_BINFS=y
|
||||
CONFIG_FS_FAT=y
|
||||
CONFIG_FS_HOSTFS=y
|
||||
CONFIG_FS_PROCFS=y
|
||||
CONFIG_FS_RAMMAP=y
|
||||
CONFIG_FS_ROMFS=y
|
||||
CONFIG_GPIO_LOWER_HALF=y
|
||||
CONFIG_IDLETHREAD_STACKSIZE=4096
|
||||
CONFIG_INIT_ENTRYPOINT="nsh_main"
|
||||
CONFIG_IOEXPANDER=y
|
||||
CONFIG_IOEXPANDER_DUMMY=y
|
||||
CONFIG_LIBC_ENVPATH=y
|
||||
CONFIG_LIBC_EXECFUNCS=y
|
||||
CONFIG_LIBC_LOCALE=y
|
||||
CONFIG_LIBC_LOCALE_CATALOG=y
|
||||
CONFIG_LIBC_LOCALE_GETTEXT=y
|
||||
CONFIG_LIBC_MAX_EXITFUNS=1
|
||||
CONFIG_LIBC_NUMBERED_ARGS=y
|
||||
CONFIG_NDEBUG=y
|
||||
CONFIG_NSH_BUILTIN_APPS=y
|
||||
CONFIG_NSH_FILE_APPS=y
|
||||
CONFIG_NSH_READLINE=y
|
||||
CONFIG_PATH_INITIAL="/bin"
|
||||
CONFIG_PIPES=y
|
||||
CONFIG_PSEUDOFS_ATTRIBUTES=y
|
||||
CONFIG_PSEUDOFS_FILE=y
|
||||
CONFIG_PSEUDOFS_SOFTLINKS=y
|
||||
CONFIG_READLINE_TABCOMPLETION=y
|
||||
CONFIG_RTC=y
|
||||
CONFIG_RTC_ARCH=y
|
||||
CONFIG_RTC_DRIVER=y
|
||||
CONFIG_SCHED_BACKTRACE=y
|
||||
CONFIG_SCHED_EVENTS=y
|
||||
CONFIG_SCHED_HAVE_PARENT=y
|
||||
CONFIG_SCHED_WAITPID=y
|
||||
CONFIG_SIM_HOSTFS=y
|
||||
CONFIG_SIM_WALLTIME_SIGNAL=y
|
||||
CONFIG_START_MONTH=6
|
||||
CONFIG_START_YEAR=2008
|
||||
CONFIG_SYSTEM_DUMPSTACK=y
|
||||
CONFIG_SYSTEM_NSH=y
|
||||
CONFIG_TESTING_CMOCKA=y
|
||||
CONFIG_TESTING_DRIVER_TEST=y
|
||||
CONFIG_WATCHDOG=y
|
||||
CONFIG_WATCHDOG_AUTOMONITOR=y
|
||||
CONFIG_WATCHDOG_AUTOMONITOR_BY_CAPTURE=y
|
||||
CONFIG_WATCHDOG_TIMEOUT_NOTIFIER=y
|
||||
|
|
@ -42,6 +42,7 @@
|
|||
#include <nuttx/panic_notifier.h>
|
||||
#include <nuttx/power/pm.h>
|
||||
#include <nuttx/mutex.h>
|
||||
#include <nuttx/spinlock.h>
|
||||
#include <nuttx/wdog.h>
|
||||
#include <nuttx/wqueue.h>
|
||||
#include <nuttx/timers/oneshot.h>
|
||||
|
|
@ -99,6 +100,9 @@ struct watchdog_upperhalf_s
|
|||
struct notifier_block nb;
|
||||
#endif
|
||||
#ifdef CONFIG_WATCHDOG_AUTOMONITOR
|
||||
# if defined(CONFIG_WATCHDOG_AUTOMONITOR_BY_CAPTURE)
|
||||
FAR struct watchdog_upperhalf_s *capture_next;
|
||||
# endif
|
||||
# if defined(CONFIG_WATCHDOG_AUTOMONITOR_BY_ONESHOT)
|
||||
FAR struct oneshot_lowerhalf_s *oneshot;
|
||||
# elif defined(CONFIG_WATCHDOG_AUTOMONITOR_BY_TIMER)
|
||||
|
|
@ -153,24 +157,129 @@ static const struct file_operations g_wdogops =
|
|||
static ATOMIC_NOTIFIER_HEAD(g_watchdog_notifier_list);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_WATCHDOG_AUTOMONITOR_BY_CAPTURE
|
||||
/* Active capture automonitor instances. Lower halves that pass an argument
|
||||
* can identify their upper-half directly or through the lower-half pointer.
|
||||
* A NULL argument is accepted only when this list contains one instance.
|
||||
*/
|
||||
|
||||
static FAR struct watchdog_upperhalf_s *g_watchdog_capture_list;
|
||||
static spinlock_t g_watchdog_capture_lock = SP_UNLOCKED;
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(CONFIG_WATCHDOG_AUTOMONITOR_BY_CAPTURE)
|
||||
#ifdef CONFIG_WATCHDOG_AUTOMONITOR_BY_CAPTURE
|
||||
static void watchdog_capture_add(FAR struct watchdog_upperhalf_s *upper)
|
||||
{
|
||||
irqstate_t flags = spin_lock_irqsave(&g_watchdog_capture_lock);
|
||||
|
||||
upper->capture_next = g_watchdog_capture_list;
|
||||
g_watchdog_capture_list = upper;
|
||||
spin_unlock_irqrestore(&g_watchdog_capture_lock, flags);
|
||||
}
|
||||
|
||||
static void watchdog_capture_remove(FAR struct watchdog_upperhalf_s *upper)
|
||||
{
|
||||
FAR struct watchdog_upperhalf_s **cursor;
|
||||
irqstate_t flags = spin_lock_irqsave(&g_watchdog_capture_lock);
|
||||
|
||||
cursor = &g_watchdog_capture_list;
|
||||
while (*cursor != NULL)
|
||||
{
|
||||
if (*cursor == upper)
|
||||
{
|
||||
*cursor = upper->capture_next;
|
||||
upper->capture_next = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
cursor = &(*cursor)->capture_next;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&g_watchdog_capture_lock, flags);
|
||||
}
|
||||
|
||||
static FAR struct watchdog_upperhalf_s *
|
||||
watchdog_capture_find(FAR void *arg)
|
||||
{
|
||||
FAR struct watchdog_upperhalf_s *upper;
|
||||
FAR struct watchdog_upperhalf_s *match = NULL;
|
||||
irqstate_t flags = spin_lock_irqsave(&g_watchdog_capture_lock);
|
||||
|
||||
if (arg == NULL)
|
||||
{
|
||||
for (upper = g_watchdog_capture_list; upper != NULL;
|
||||
upper = upper->capture_next)
|
||||
{
|
||||
if (match != NULL)
|
||||
{
|
||||
/* More than one NULL-context instance cannot be identified. */
|
||||
|
||||
match = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
match = upper;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (upper = g_watchdog_capture_list; upper != NULL;
|
||||
upper = upper->capture_next)
|
||||
{
|
||||
if (arg == upper || arg == upper->lower)
|
||||
{
|
||||
match = upper;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&g_watchdog_capture_lock, flags);
|
||||
return match;
|
||||
}
|
||||
|
||||
static int watchdog_automonitor_capture(int irq, FAR void *context,
|
||||
FAR void *arg)
|
||||
{
|
||||
FAR struct watchdog_upperhalf_s *upper = arg;
|
||||
FAR struct watchdog_lowerhalf_s *lower = upper->lower;
|
||||
FAR struct watchdog_upperhalf_s *upper = watchdog_capture_find(arg);
|
||||
FAR struct watchdog_lowerhalf_s *lower;
|
||||
|
||||
/* A stop operation can race with a pending interrupt. Do not dereference
|
||||
* a removed association after automonitor has been stopped.
|
||||
*/
|
||||
|
||||
if (upper == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
lower = upper->lower;
|
||||
|
||||
if (upper->monitor)
|
||||
{
|
||||
/* Reload the hardware watchdog before dispatching optional
|
||||
* notifications. The EWI-to-reset interval is short, and notifier
|
||||
* callbacks must not delay the keepalive operation.
|
||||
*/
|
||||
|
||||
lower->ops->keepalive(lower);
|
||||
|
||||
#ifdef CONFIG_WATCHDOG_TIMEOUT_NOTIFIER
|
||||
/* The capture callback is entered from the watchdog timeout
|
||||
* interrupt. Notifier callbacks must be safe in interrupt context.
|
||||
*/
|
||||
|
||||
watchdog_automonitor_timeout();
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined(CONFIG_WATCHDOG_AUTOMONITOR_BY_ONESHOT)
|
||||
static void
|
||||
watchdog_automonitor_oneshot(FAR struct oneshot_lowerhalf_s *oneshot,
|
||||
|
|
@ -267,6 +376,7 @@ watchdog_automonitor_start(FAR struct watchdog_upperhalf_s *upper)
|
|||
if (!upper->monitor)
|
||||
{
|
||||
# if defined(CONFIG_WATCHDOG_AUTOMONITOR_BY_CAPTURE)
|
||||
watchdog_capture_add(upper);
|
||||
lower->ops->capture(lower, watchdog_automonitor_capture);
|
||||
# elif defined(CONFIG_WATCHDOG_AUTOMONITOR_BY_ONESHOT)
|
||||
struct timespec ts =
|
||||
|
|
@ -311,6 +421,7 @@ static void watchdog_automonitor_stop(FAR struct watchdog_upperhalf_s *upper)
|
|||
lower->ops->stop(lower);
|
||||
# if defined(CONFIG_WATCHDOG_AUTOMONITOR_BY_CAPTURE)
|
||||
lower->ops->capture(lower, NULL);
|
||||
watchdog_capture_remove(upper);
|
||||
# elif defined(CONFIG_WATCHDOG_AUTOMONITOR_BY_ONESHOT)
|
||||
ONESHOT_CANCEL(upper->oneshot, NULL);
|
||||
# elif defined(CONFIG_WATCHDOG_AUTOMONITOR_BY_TIMER)
|
||||
|
|
@ -762,7 +873,12 @@ void watchdog_notifier_chain_unregister(FAR struct notifier_block *nb)
|
|||
|
||||
void watchdog_automonitor_timeout(void)
|
||||
{
|
||||
atomic_notifier_call_chain(&g_watchdog_notifier_list, action, data);
|
||||
/* The action identifies the automonitor keepalive mechanism selected at
|
||||
* build time. There is no source-specific payload for this event.
|
||||
*/
|
||||
|
||||
atomic_notifier_call_chain(&g_watchdog_notifier_list,
|
||||
WATCHDOG_NOTIFIER_ACTION, NULL);
|
||||
}
|
||||
#endif /* CONFIG_WATCHDOG_TIMEOUT_NOTIFIER */
|
||||
|
||||
|
|
|
|||
|
|
@ -258,9 +258,12 @@ void watchdog_notifier_chain_unregister(FAR struct notifier_block *nb);
|
|||
* Name: watchdog_automonitor_timeout
|
||||
*
|
||||
* Description:
|
||||
* This function can be called in the watchdog timeout interrupt handler.
|
||||
* If so, callbacks on the watchdog timer notify chain are called when the
|
||||
* watchdog timer times out.
|
||||
* Notify callbacks registered on the watchdog timeout notifier chain.
|
||||
* The action identifies the automonitor keepalive mechanism selected by
|
||||
* CONFIG_WATCHDOG_AUTOMONITOR_BY_*. The callback data argument is NULL.
|
||||
*
|
||||
* This function is intended to be called from a watchdog timeout interrupt
|
||||
* handler. Callback functions must obey interrupt-context restrictions.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue