[PATCH 3/4] lib: sbi: Add SBI watchdog framework

Himanshu Chauhan himanshu.chauhan at oss.qualcomm.com
Thu Oct 22 21:55:28 PDT 2026


Hi Prajwal,

On Fri, Oct 02, 2026 at 02:00:39PM +0530, Prajwal N wrote:
> Update the build infrastructure to include the SBI
> watchdog compilation.
> 
> Implement the SBI watchdog functionality including
> start, stop, pat, read and write attributes,
> pretimeout and timeout handlers.
> 
> Signed-off-by: Prajwal N <prajwal.n at oss.qualcomm.com>
> ---
>  include/sbi/sbi_wdt.h |  72 +++++++
>  lib/sbi/objects.mk    |   1 +
>  lib/sbi/sbi_init.c    |   8 +
>  lib/sbi/sbi_wdt.c     | 455 ++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 536 insertions(+)
>  create mode 100644 include/sbi/sbi_wdt.h
>  create mode 100644 lib/sbi/sbi_wdt.c
> 
> diff --git a/include/sbi/sbi_wdt.h b/include/sbi/sbi_wdt.h
> new file mode 100644
> index 00000000..43f866dc
> --- /dev/null
> +++ b/include/sbi/sbi_wdt.h
> @@ -0,0 +1,72 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2026 Qualcomm Inc.
> + *
> + * Authors:
> + *   Prajwal N <prajwal.n at oss.qualcomm.com>
> + */
> +
> +#ifndef __SBI_WDT_H__
> +#define __SBI_WDT_H__
> +
> +/**
> + * Read the watchdog attribute
> + * @param attribute_id The wdt attribute id to be read
> + * @param attribute_value The value of attribute returned
> + * @return int error
> + */
> +int sbi_watchdog_read_attribute(u32 attribute_id, u32* attribute_value);
> +
> +/**
> + * Write the watchdog attribute
> + * @param attribute_id The wdt attribute id to be written
> + * @param attribute_value The wdt attribute value to be written
> + * @return int error
> + */
> +int sbi_watchdog_write_attribute(u32 attribute_id, u32 attribute_value);
> +
> +/**
> + * Write the watchdog MSI message attribute
> + * @param msi_addr_low The value of MSI low address
> + * @param msi_addr_high The value of MSI high address
> + * @param msi_data The value of MSI data
> + * @return int error
> + */
> +int sbi_watchdog_write_notif_msi_message(u32 msi_addr_low, u32 msi_addr_high, u32 msi_data);
> +
> +/**
> + * Start the watchdog
> + * @param void
> + * @return int error
> + */
> +int sbi_watchdog_start(void);
> +
> +/**
> + * Stop the watchdog
> + * @param void
> + * @return int error
> + */
> +int sbi_watchdog_stop(void);
> +
> +/**
> + * Pat the watchdog
> + * @param void
> + * @return int error
> + */
> +int sbi_watchdog_pat(void);
> +
> +/**
> + * Initialize the watchdog
> + * @param void
> + * @return int error
> + */
> +int sbi_watchdog_init(void);
> +
> +/**
> + * Remove the watchdog
> + * @param void
> + * @return int error
> + */
> +int sbi_watchdog_exit(void);
> +#endif
> diff --git a/lib/sbi/objects.mk b/lib/sbi/objects.mk
> index ae27d0c5..c8bdc94a 100644
> --- a/lib/sbi/objects.mk
> +++ b/lib/sbi/objects.mk
> @@ -106,5 +106,6 @@ endif
>  libsbi-objs-y += sbi_unpriv.o
>  libsbi-objs-y += sbi_expected_trap.o
>  libsbi-objs-y += sbi_cppc.o
> +libsbi-objs-y += sbi_wdt.o
>  libsbi-objs-$(CC_SUPPORT_VECTOR) += sbi_vector.o
>  libsbi-objs-y += sbi_fp.o
> diff --git a/lib/sbi/sbi_init.c b/lib/sbi/sbi_init.c
> index acd2f8b6..a8ce0a63 100644
> --- a/lib/sbi/sbi_init.c
> +++ b/lib/sbi/sbi_init.c
> @@ -35,6 +35,7 @@
>  #include <sbi/sbi_tlb.h>
>  #include <sbi/sbi_version.h>
>  #include <sbi/sbi_unit_test.h>
> +#include <sbi/sbi_wdt.h>
>  
>  #define BANNER                                              \
>  	"   ____                    _____ ____ _____\n"     \
> @@ -365,6 +366,13 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
>  		sbi_hart_hang();
>  	}
>  
> +	/* Initialise the watchdog*/
> +	rc = sbi_watchdog_init();
> +	if (rc) {
> +		sbi_printf("%s: watchdog init failed (error %d)\n", __func__, rc);
> +		sbi_hart_hang();
> +	}
> +
>  	/*
>  	 * Note: Finalize domains after HSM initialization
>  	 * Note: Finalize domains before HART PMP configuration so
> diff --git a/lib/sbi/sbi_wdt.c b/lib/sbi/sbi_wdt.c
> new file mode 100644
> index 00000000..988c6581
> --- /dev/null
> +++ b/lib/sbi/sbi_wdt.c
> @@ -0,0 +1,455 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2026 Qualcomm Inc.
> + *
> + * Authors:
> + *   Prajwal N <prajwal.n at oss.qualcomm.com>
> + */
> +
> +#include <sbi/riscv_asm.h>
> +#include <sbi/sbi_error.h>
> +#include <sbi/sbi_ecall.h>
> +#include <sbi/sbi_bitops.h>
> +#include <sbi/sbi_ecall_interface.h>
> +#include <sbi/riscv_locks.h>
> +#include <sbi/sbi_heap.h>
> +#include <sbi/sbi_irqchip.h>
> +#include <sbi/sbi_timer.h>
> +#include <sbi/sbi_wdt.h>
> +#include <sbi/sbi_system.h>
> +#include <sbi/sbi_console.h>
> +#include <sbi/riscv_io.h>
> +#include <sbi/sbi_string.h>
> +#include <sbi/sbi_hart_protection.h>
> +
> +/** Watchdog capabitlity - MSI */
> +#define WDT_CAP_MSI_MASK	BIT(1)
> +
> +/** Watchdog capabitlity - SSE */
> +#define WDT_CAP_SSE_MASK	BIT(0)
> +
> +/**
> + * Helpers to enable/disable channel capability bits
> + * _c: capability variable
> + * _m: capability mask
> + */
> +#define CAP_ENABLE(_c, _m)	INSERT_FIELD(_c, _m, 1)
> +#define CAP_DISABLE(_c, _m)	INSERT_FIELD(_c, _m, 0)
> +#define CAP_GET(_c, _m)		EXTRACT_FIELD(_c, _m)
> +
> +/* Watchdog Permission Flags */
> +#define WDT_ATTR_PERM_RO	BIT(0)
> +#define WDT_ATTR_PERM_W	 BIT(1)
> +#define WDT_ATTR_PERM_RW	(WDT_ATTR_PERM_RO) | (WDT_ATTR_PERM_W)
> +
> +static const u32 sbi_watchdog_attr_perm[SBI_WDT_ATTR_MAX] = {
> +	[SBI_WDT_CAPABILITY]            = WDT_ATTR_PERM_RO,
> +	[SBI_WDT_STATE]                 = WDT_ATTR_PERM_RO,
> +	[SBI_WDT_MIN_PERIOD]            = WDT_ATTR_PERM_RO,
> +	[SBI_WDT_PERIOD]                = WDT_ATTR_PERM_RW,
> +	[SBI_WDT_TIME_LEFT]             = WDT_ATTR_PERM_RO,
> +	[SBI_WDT_NOTIF_TIME]            = WDT_ATTR_PERM_RW,
> +	[SBI_WDT_NOTIF_MSI_ADDR_LOW]    = WDT_ATTR_PERM_RW,
> +	[SBI_WDT_NOTIF_MSI_ADDR_HIGH]   = WDT_ATTR_PERM_RW,
> +	[SBI_WDT_NOTIF_MSI_DATA]        = WDT_ATTR_PERM_RW
> +};
> +
> +/**
> + * SBI watchdog state
> + */
> +typedef enum {
> +	SBI_WDT_STOPPED = 0,
> +	SBI_WDT_RUNNING	= 1,
> +	SBI_WDT_PAUSED  = 2,
> +	SBI_WDT_EXPIRED	= 3
> +} sbi_wdt_state_t;
> +
> +/**
> + * SBI watchdog attributes
> + */
> +struct sbi_watchdog_attrs {
> +	/* MSI and SSE capability flags */
> +	u32 wdt_capability;
> +	/* Watchdog state */
> +	u32 wdt_state;
> +	/* Minimum watchdog timeout supported in us */
> +	u32 wdt_min_period;
> +	/* Watchdog timeout period in us */
> +	u32 wdt_period;
> +	/* Time left until watchdog expiry in us */
> +	u32 wdt_time_left;
> +	/* Watchdog pretimeout in us */
> +	u32 wdt_notif_time;
> +	/* MSI target address low 32-bit */
> +	u32 wdt_notif_msi_addr_low;
> +	/* MSI target address high 32-bit */
> +	u32 wdt_notif_msi_addr_high;
> +	/* MSI data */
> +	u32 wdt_notif_msi_data;
> +};
> +
> +struct sbi_watchdog {
> +	/* Watchdog attributes */
> +	struct sbi_watchdog_attrs wdt_attr;
> +	/* Watchdog timeout event */
> +	struct sbi_timer_event wdt_timer_ev;
> +	/* Watchdog pretimeout event */
> +	struct sbi_timer_event wdt_pretimeout_ev;
> +	/* Watchdog spinlock */
> +	spinlock_t wdt_lock;
> +};
> +
> +/* Global pointer to the watchdog structure */
> +static struct sbi_watchdog *sbi_system_watchdog;
> +
> +/** Make sure all the attributes are packed for direct memcpy in ATTR_READ */
> +#define assert_field_offset(field, attr_offset)				\
> +	_Static_assert(							\
> +		((offsetof(struct sbi_watchdog_attrs, field)) /		\
> +			sizeof(u32)) == attr_offset,			\
> +		"field" #field						\
> +		" from struct sbi_watchdog_attrs invalid offset, expected " #attr_offset)
> +
> +assert_field_offset(wdt_capability, SBI_WDT_CAPABILITY);
> +assert_field_offset(wdt_state, SBI_WDT_STATE);
> +assert_field_offset(wdt_min_period, SBI_WDT_MIN_PERIOD);
> +assert_field_offset(wdt_period, SBI_WDT_PERIOD);
> +assert_field_offset(wdt_time_left, SBI_WDT_TIME_LEFT);
> +assert_field_offset(wdt_notif_time, SBI_WDT_NOTIF_TIME);
> +assert_field_offset(wdt_notif_msi_addr_low, SBI_WDT_NOTIF_MSI_ADDR_LOW);
> +assert_field_offset(wdt_notif_msi_addr_high, SBI_WDT_NOTIF_MSI_ADDR_HIGH);
> +assert_field_offset(wdt_notif_msi_data, SBI_WDT_NOTIF_MSI_DATA);
> +
> +int sbi_watchdog_read_attribute(u32 attribute_id, u32* attribute_value)
> +{
> +	u64 current, deadline, tick_delta;
> +	int ret = SBI_SUCCESS;
> +
> +	spin_lock(&sbi_system_watchdog->wdt_lock);
> +
> +	switch (attribute_id) {
> +	case SBI_WDT_TIME_LEFT:
> +		/* Calculate the time left before expiry and update the attribute */
> +		current = sbi_timer_value();
> +		deadline = sbi_system_watchdog->wdt_timer_ev.time_stamp;
> +		if (current >= deadline) {
> +			sbi_system_watchdog->wdt_attr.wdt_time_left = 0;
> +			break;
> +		}
> +		tick_delta = deadline - current;
> +		sbi_system_watchdog->wdt_attr.wdt_time_left = sbi_timer_ticks_to_usec(tick_delta);
> +		break;
> +
> +	default:
> +		/* Return error if the attribute index is out of bound*/
> +		if (attribute_id >= SBI_WDT_ATTR_MAX) {
> +			ret = SBI_ERR_INVALID_PARAM;
> +			goto out;
> +		}
> +		break;
> +	}
> +
> +	u32 *wdt_attrs = (u32 *)&sbi_system_watchdog->wdt_attr;
> +	*attribute_value = wdt_attrs[attribute_id];
> +
> +out:
> +	spin_unlock(&sbi_system_watchdog->wdt_lock);
> +	return ret;
> +}
> +
> +int sbi_watchdog_write_attribute(u32 attribute_id, u32 attribute_value)
> +{
> +	int ret;
> +
> +	spin_lock(&sbi_system_watchdog->wdt_lock);
> +
> +	/* Check if the attribute is writable */
> +	if (!(sbi_watchdog_attr_perm[attribute_id] & WDT_ATTR_PERM_W)) {
This is unbounded access. Please validate attribute_id against SBI_WDT_ATTR_MAX before access.

> +		ret = SBI_ERR_DENIED;
> +		goto out;
> +	}
> +
> +	switch (attribute_id) {
> +	case SBI_WDT_PERIOD:
> +		/* Return error if wdt_period passed is less than wdt_min_period */
> +		if (attribute_value < sbi_system_watchdog->wdt_attr.wdt_min_period) {
> +			ret = SBI_ERR_FAILED;
> +			goto out;
> +		}
> +		break;
> +
> +	case SBI_WDT_NOTIF_TIME:
> +		/* Ignore the write if the MSI capability is not enabled */
> +		if (!CAP_GET(sbi_system_watchdog->wdt_attr.wdt_capability, WDT_CAP_MSI_MASK)) {
> +			ret = SBI_SUCCESS;
> +			goto out;
> +		}
> +
> +		/* Returen error if the notif time is greater than the timeout period*/
Typo.

> +		if (attribute_value >= sbi_system_watchdog->wdt_attr.wdt_period) {
> +			ret = SBI_ERR_FAILED;
> +			goto out;
> +		}
> +		break;
> +
> +	case SBI_WDT_NOTIF_MSI_ADDR_LOW:
> +	case SBI_WDT_NOTIF_MSI_ADDR_HIGH:
> +	case SBI_WDT_NOTIF_MSI_DATA:
> +		/* Ignore the write if the MSI capability is not enabled */
> +		if (!CAP_GET(sbi_system_watchdog->wdt_attr.wdt_capability, WDT_CAP_MSI_MASK)) {
> +			ret = SBI_SUCCESS;
> +			goto out;
> +		}
> +
> +		/*
> +		 * The MSI address and data can be written only when
> +		 * the notifications are disabled
> +		 */
> +		if (sbi_system_watchdog->wdt_attr.wdt_notif_time != 0) {
> +			ret = SBI_ERR_FAILED;
> +			goto out;
> +		}
> +		break;
> +
> +	default:
> +		/* Return error if the attribute index is out of bound*/
> +		if (attribute_id >= SBI_WDT_ATTR_MAX) {
> +			ret = SBI_ERR_INVALID_PARAM;
> +			goto out;
> +		}
> +		break;
> +	}
> +
> +	u32 *wdt_attrs = (u32 *)&sbi_system_watchdog->wdt_attr;
> +	wdt_attrs[attribute_id] = attribute_value;
> +
> +	ret = SBI_SUCCESS;
> +
> +out:
> +	spin_unlock(&sbi_system_watchdog->wdt_lock);
> +	return ret;
> +}
> +
> +int sbi_watchdog_write_notif_msi_message(u32 msi_addr_low, u32 msi_addr_high, u32 msi_data)
> +{
> +	int ret;
> +
> +	spin_lock(&sbi_system_watchdog->wdt_lock);
> +
> +	/* Ignore the write if the MSI capability is not enabled */
> +	if (!CAP_GET(sbi_system_watchdog->wdt_attr.wdt_capability, WDT_CAP_MSI_MASK)) {
> +		ret = SBI_SUCCESS;
> +		goto out;
> +	}
> +
> +	/* The MSI address and data can be written only when the notifications are disabled */
> +	if (sbi_system_watchdog->wdt_attr.wdt_notif_time != 0) {
> +		ret = SBI_EINVAL;
> +		goto out;
> +	}
> +
> +	u32 *wdt_attrs = (u32 *)&sbi_system_watchdog->wdt_attr;
> +	wdt_attrs[SBI_WDT_NOTIF_MSI_ADDR_LOW] = msi_addr_low;
> +	wdt_attrs[SBI_WDT_NOTIF_MSI_ADDR_HIGH] = msi_addr_high;
> +	wdt_attrs[SBI_WDT_NOTIF_MSI_DATA] = msi_data;
> +
> +	ret = SBI_SUCCESS;
> +
> +out:
> +	spin_unlock(&sbi_system_watchdog->wdt_lock);
> +	return ret;
> +}
> +
> +static void sbi_watchdog_pretimeout_cleanup(struct sbi_timer_event *ev)
> +{
> +	/* Nothing to do */
> +}
> +
> +static void sbi_watchdog_pretimeout_callback(struct sbi_timer_event *ev,
> +					     struct sbi_timer_event_restart *restart)
> +{
> +	u64 msi_addr;
> +	u32 msi_data;
> +
> +	spin_lock(&sbi_system_watchdog->wdt_lock);
> +	/* Calculate the MSI address using the low and high addresses*/
> +	msi_addr = (((u64)sbi_system_watchdog->wdt_attr.wdt_notif_msi_addr_high << 32 ) |
> +					sbi_system_watchdog->wdt_attr.wdt_notif_msi_addr_low);
> +	msi_data = sbi_system_watchdog->wdt_attr.wdt_notif_msi_data;
> +
> +	spin_unlock(&sbi_system_watchdog->wdt_lock);
> +
> +	sbi_hart_protection_temp_map_range((unsigned long)msi_addr, sizeof(u32));
> +	/* Write the MSI data to the MSI address*/
> +	writel(msi_data, (void *)(unsigned long)msi_addr);
> +	sbi_hart_protection_temp_unmap_range((unsigned long)msi_addr, sizeof(u32));
> +}
> +
> +static void sbi_watchdog_event_cleanup(struct sbi_timer_event *ev)
> +{
> +	/* Nothing to do */
> +}
> +
> +static void sbi_watchdog_expired_callback(struct sbi_timer_event *ev,
> +					  struct sbi_timer_event_restart *restart)
> +{
> +	spin_lock(&sbi_system_watchdog->wdt_lock);
> +
> +	sbi_system_watchdog->wdt_attr.wdt_state = SBI_WDT_EXPIRED;
> +	/* Trigger the system reboot*/
> +	sbi_system_reset(SBI_SRST_RESET_TYPE_WARM_REBOOT, SBI_SRST_RESET_REASON_NONE);
> +
> +	spin_unlock(&sbi_system_watchdog->wdt_lock);
> +}
> +
> +static void sbi_watchdog_enable_timer_events()
> +{
This function is always called with wdt_lock held and it calls sbi_timer_event_start(), which takes the timer
event-list lock. In the following remote but possible scenario:

Hart 0: sbi_watchdog_pat()
           holds wdt_lock
           calls sbi_timer_event_start()
           waits for Hart 1's event_list_lock

 Hart 1: sbi_timer_process()
           holds event_list_lock
           invokes watchdog callback
           waits for wdt_lock

A deadlock is possible.

> +	u64 timeout, pretimeout;
> +	u32 pretimeout_us;
> +
> +	/* Restart the pretimeout event only if the wdt_notif_time is non zero*/
> +	if (sbi_system_watchdog->wdt_attr.wdt_notif_time != 0) {
> +		pretimeout_us = sbi_system_watchdog->wdt_attr.wdt_period -
> +				sbi_system_watchdog->wdt_attr.wdt_notif_time;
When writing SBI_WDT_NOTIF_TIME, its value is checked against the current SBI_WDT_PERIOD
but when writing SBI_WDT_PERIOD, the check of the new value is against wdt_min_period.
It is not checked whether the new period is still greater than the already configured wdt_notif_time.
So, it is possible that wdt_period - wdt_notif_time underflows. Am I missing something?

> +		pretimeout = sbi_timer_value() + sbi_timer_compute_udelta(pretimeout_us);
> +
> +		sbi_timer_event_start(&sbi_system_watchdog->wdt_pretimeout_ev, pretimeout);
> +	}
> +
> +	/* Restart the Watchdog timeout event only if the wdt_period is non zero*/
> +	if (sbi_system_watchdog->wdt_attr.wdt_period != 0) {
> +		timeout = sbi_timer_value() +
> +			  sbi_timer_compute_udelta(sbi_system_watchdog->wdt_attr.wdt_period);
> +		sbi_timer_event_start(&sbi_system_watchdog->wdt_timer_ev, timeout);
> +	}
> +}
> +
> +int sbi_watchdog_start(void)
> +{
> +	int ret;
> +
> +	spin_lock(&sbi_system_watchdog->wdt_lock);
> +
> +	/* Return error if the watchdog is not in SBI_WDT_STOPPED state*/
> +	if (sbi_system_watchdog->wdt_attr.wdt_state != SBI_WDT_STOPPED) {
> +		ret = SBI_ERR_INVALID_STATE;
> +		goto out;
> +	}
> +
> +	sbi_watchdog_enable_timer_events();
> +
> +	sbi_system_watchdog->wdt_attr.wdt_state = SBI_WDT_RUNNING;
> +	ret = SBI_SUCCESS;
> +
> +out:
> +	spin_unlock(&sbi_system_watchdog->wdt_lock);
> +	return ret;
> +}
> +
> +int sbi_watchdog_stop(void)
> +{
> +	int ret;
> +
> +	spin_lock(&sbi_system_watchdog->wdt_lock);
> +
> +	/* Return error if the watchdog is already in SBI_WDT_STOPPED state */
> +	if (sbi_system_watchdog->wdt_attr.wdt_state == SBI_WDT_STOPPED) {
> +		ret = SBI_ERR_INVALID_STATE;
> +		goto out;
> +	}
> +
> +	/* Stop both the pretimeout and expiry events */
> +	sbi_timer_event_stop(&sbi_system_watchdog->wdt_pretimeout_ev);
> +	sbi_timer_event_stop(&sbi_system_watchdog->wdt_timer_ev);
> +
> +	sbi_system_watchdog->wdt_attr.wdt_state = SBI_WDT_STOPPED;
> +	sbi_system_watchdog->wdt_attr.wdt_time_left = 0;
> +
> +	ret = SBI_SUCCESS;
> +
> +out:
> +	spin_unlock(&sbi_system_watchdog->wdt_lock);
> +	return ret;
> +}
> +
> +int sbi_watchdog_pat(void)
> +{
> +	int ret;
> +
> +	spin_lock(&sbi_system_watchdog->wdt_lock);
> +
> +	/* Return error if the watchdog is not in SBI_WDT_RUNNING state*/
> +	if (sbi_system_watchdog->wdt_attr.wdt_state != SBI_WDT_RUNNING) {
> +		ret = SBI_ERR_INVALID_STATE;
> +		goto out;
> +	}
> +
> +	sbi_watchdog_enable_timer_events();
> +	ret = SBI_SUCCESS;
> +
> +out:
> +	spin_unlock(&sbi_system_watchdog->wdt_lock);
> +	return ret;
> +}
> +
> +static void sbi_watchdog_init_attributes(void)
> +{
> +	const struct sbi_timer_device *tdev;
> +	unsigned long timer_freq;
> +	u32 capability = 0;
> +
> +	spin_lock(&sbi_system_watchdog->wdt_lock);
> +
> +	sbi_memset(&sbi_system_watchdog->wdt_attr, 0, sizeof(struct sbi_watchdog_attrs));
> +
> +	/* Retrieve the MSI capability from irqchip */
> +	if (sbi_irqchip_find_device_by_caps(SBI_IRQCHIP_CAPS_MSI, NULL))
> +		capability = CAP_ENABLE(capability, WDT_CAP_MSI_MASK);
> +
> +	sbi_system_watchdog->wdt_attr.wdt_capability = capability;
> +
> +	sbi_system_watchdog->wdt_attr.wdt_state = SBI_WDT_STOPPED;
> +
> +	/* Set the min period based on the timer frequency */
> +	tdev = sbi_timer_get_device();
> +	if (tdev != NULL) {
> +		timer_freq = tdev->timer_freq;
> +		/* Ceil division to ensure the result is non-zero */
> +		sbi_system_watchdog->wdt_attr.wdt_min_period =
> +					(u32)((SEC_TO_MICROSEC + timer_freq - 1) / timer_freq);
> +	}
> +
> +	spin_unlock(&sbi_system_watchdog->wdt_lock);
> +}
> +
> +int sbi_watchdog_init(void)
> +{
> +	/* Allocate memory for global watchdog structure sbi_system_watchdog */
> +	sbi_system_watchdog = (struct sbi_watchdog*)sbi_zalloc(sizeof(struct sbi_watchdog));
> +
> +	if(!sbi_system_watchdog) {
> +		return SBI_ENOMEM;
> +	}
> +
> +	SPIN_LOCK_INIT(sbi_system_watchdog->wdt_lock);
> +	SBI_INIT_TIMER_EVENT(&sbi_system_watchdog->wdt_timer_ev,
> +			     sbi_watchdog_expired_callback,
> +			     sbi_watchdog_event_cleanup, NULL);
> +	SBI_INIT_TIMER_EVENT(&sbi_system_watchdog->wdt_pretimeout_ev,
> +			     sbi_watchdog_pretimeout_callback,
> +			     sbi_watchdog_pretimeout_cleanup, NULL);
> +
> +	/* Initialize the default watchdog attributes */
> +	sbi_watchdog_init_attributes();
> +
> +	return SBI_SUCCESS;
> +}
> +
> +int sbi_watchdog_exit(void)
> +{
> +	/* Clean up the global watchdog */
> +	sbi_free(sbi_system_watchdog);
> +
> +	return 0;
> +}
> -- 
> 2.43.0
> 
> 
> -- 
> opensbi mailing list
> opensbi at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/opensbi



More information about the opensbi mailing list