drivers/char/ipmi/ipmi_watchdog.c

Source file repositories/reference/linux-study-clean/drivers/char/ipmi/ipmi_watchdog.c

File Facts

System
Linux kernel
Corpus path
drivers/char/ipmi/ipmi_watchdog.c
Extension
.c
Size
32192 bytes
Lines
1326
Domain
Driver Families
Bucket
drivers/char
Inferred role
Driver Families: operation-table or driver-model contract
Status
pattern 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

static const struct file_operations ipmi_wdog_fops = {
	.owner   = THIS_MODULE,
	.read    = ipmi_read,
	.poll    = ipmi_poll,
	.write   = ipmi_write,
	.unlocked_ioctl = ipmi_unlocked_ioctl,
	.compat_ioctl	= compat_ptr_ioctl,
	.open    = ipmi_open,
	.release = ipmi_close,
	.fasync  = ipmi_fasync,
};

static struct miscdevice ipmi_wdog_miscdev = {
	.minor		= WATCHDOG_MINOR,
	.name		= "watchdog",
	.fops		= &ipmi_wdog_fops
};

static void ipmi_wdog_msg_handler(struct ipmi_recv_msg *msg,
				  void                 *handler_data)
{
	if (msg->msg.cmd == IPMI_WDOG_RESET_TIMER &&
			msg->msg.data[0] == IPMI_WDOG_TIMER_NOT_INIT_RESP)
		pr_info("response: The IPMI controller appears to have been reset, will attempt to reinitialize the watchdog timer\n");
	else if (msg->msg.data[0] != 0)
		pr_err("response: Error %x on cmd %x\n",
		       msg->msg.data[0],
		       msg->msg.cmd);

	ipmi_free_recv_msg(msg);
}

static void ipmi_wdog_pretimeout_handler(void *handler_data)
{
	if (preaction_val != WDOG_PRETIMEOUT_NONE) {
		if (preop_val == WDOG_PREOP_PANIC) {
			if (atomic_inc_and_test(&preop_panic_excl))
				panic("Watchdog pre-timeout");
		} else if (preop_val == WDOG_PREOP_GIVE_DATA) {
			mutex_lock(&ipmi_read_mutex);
			data_to_read = 1;
			wake_up_interruptible(&read_q);
			kill_fasync(&fasync_q, SIGIO, POLL_IN);
			mutex_unlock(&ipmi_read_mutex);
		}
	}

	/*
	 * On some machines, the heartbeat will give an error and not
	 * work unless we re-enable the timer.  So do so.
	 */
	atomic_set(&pretimeout_since_last_heartbeat, 1);
}

static void ipmi_wdog_panic_handler(void *user_data)
{
	static int panic_event_handled;

	/*
	 * On a panic, if we have a panic timeout, make sure to extend
	 * the watchdog timer to a reasonable value to complete the
	 * panic, if the watchdog timer is running.  Plus the
	 * pretimeout is meaningless at panic time.
	 */
	if (watchdog_user && !panic_event_handled &&
	    ipmi_watchdog_state != WDOG_TIMEOUT_NONE) {
		/* Make sure we do this only once. */
		panic_event_handled = 1;

		timeout = panic_wdt_timeout;
		pretimeout = 0;
		panic_halt_ipmi_set_timeout();
	}
}

static const struct ipmi_user_hndl ipmi_hndlrs = {
	.ipmi_recv_hndl           = ipmi_wdog_msg_handler,
	.ipmi_watchdog_pretimeout = ipmi_wdog_pretimeout_handler,
	.ipmi_panic_handler       = ipmi_wdog_panic_handler
};

static void ipmi_register_watchdog(int ipmi_intf)
{
	int rv = -EBUSY;

	if (watchdog_user)
		goto out;

	if ((ifnum_to_use >= 0) && (ifnum_to_use != ipmi_intf))
		goto out;

Annotation

Implementation Notes