drivers/watchdog/watchdog_core.c

Source file repositories/reference/linux-study-clean/drivers/watchdog/watchdog_core.c

File Facts

System
Linux kernel
Corpus path
drivers/watchdog/watchdog_core.c
Extension
.c
Size
13615 bytes
Lines
499
Domain
Driver Families
Bucket
drivers/watchdog
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (wdd_tmp == wdd) {
			list_del(&wdd_tmp->deferred);
			break;
		}
	}
}

static void watchdog_check_min_max_timeout(struct watchdog_device *wdd)
{
	/*
	 * Check that we have valid min and max timeout values, if
	 * not reset them both to 0 (=not used or unknown)
	 */
	if (!wdd->max_hw_heartbeat_ms && wdd->min_timeout > wdd->max_timeout) {
		pr_info("Invalid min and max timeout values, resetting to 0!\n");
		wdd->min_timeout = 0;
		wdd->max_timeout = 0;
	}
}

/**
 * watchdog_init_timeout() - initialize the timeout field
 * @wdd: watchdog device
 * @timeout_parm: timeout module parameter
 * @dev: Device that stores the timeout-sec property
 *
 * Initialize the timeout field of the watchdog_device struct with either the
 * timeout module parameter (if it is valid value) or the timeout-sec property
 * (only if it is a valid value and the timeout_parm is out of bounds).
 * If none of them are valid then we keep the old value (which should normally
 * be the default timeout value). Note that for the module parameter, '0' means
 * 'use default' while it is an invalid value for the timeout-sec property.
 * It should simply be dropped if you want to use the default value then.
 *
 * A zero is returned on success or -EINVAL if all provided values are out of
 * bounds.
 */
int watchdog_init_timeout(struct watchdog_device *wdd,
			  unsigned int timeout_parm,
			  const struct device *dev)
{
	const char *dev_str = wdd->parent ? dev_name(wdd->parent) :
			      (const char *)wdd->info->identity;
	unsigned int t = 0;
	int ret = 0;

	watchdog_check_min_max_timeout(wdd);

	/* check the driver supplied value (likely a module parameter) first */
	if (timeout_parm) {
		if (!watchdog_timeout_invalid(wdd, timeout_parm)) {
			wdd->timeout = timeout_parm;
			return 0;
		}
		pr_err("%s: driver supplied timeout (%u) out of range\n",
			dev_str, timeout_parm);
		ret = -EINVAL;
	}

	/* try to get the timeout_sec property */
	if (dev && device_property_read_u32(dev, "timeout-sec", &t) == 0) {
		if (t && !watchdog_timeout_invalid(wdd, t)) {
			wdd->timeout = t;
			return 0;
		}
		pr_err("%s: DT supplied timeout (%u) out of range\n", dev_str, t);
		ret = -EINVAL;
	}

	if (ret < 0 && wdd->timeout)
		pr_warn("%s: falling back to default timeout (%u)\n", dev_str,
			wdd->timeout);

	return ret;
}
EXPORT_SYMBOL_GPL(watchdog_init_timeout);

static int watchdog_reboot_notifier(struct notifier_block *nb,
				    unsigned long code, void *data)
{
	struct watchdog_device *wdd;

	wdd = container_of(nb, struct watchdog_device, reboot_nb);
	if (code == SYS_DOWN || code == SYS_HALT || code == SYS_POWER_OFF) {
		if (watchdog_hw_running(wdd)) {
			int ret;

			ret = wdd->ops->stop(wdd);
			trace_watchdog_stop(wdd, ret);
			if (ret)

Annotation

Implementation Notes