⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ar531x-wdt.c

📁 atheros ar531x watchdog driver
💻 C
字号:
/* * This file is subject to the terms and conditions of the GNU General Public * License.  See the file "COPYING" in the main directory of this archive * for more details. * * Copyright © 2003 Atheros Communications, Inc.,  All Rights Reserved. *//* * Support for the Watchdog Timer */#include <linux/config.h>#include <linux/module.h>#include <linux/version.h>#include <linux/types.h>#include <linux/errno.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/miscdevice.h>#include <linux/watchdog.h>#include <linux/slab.h>#include <linux/ioport.h>#include <linux/fcntl.h>#include <asm/io.h>#include <asm/uaccess.h>#include <asm/system.h>#include <asm/delay.h>#include <linux/notifier.h>#include <linux/reboot.h>#include <linux/init.h>#include <linux/spinlock.h>#include <linux/smp_lock.h>#include <linux/wait.h>#include "ar531xlnx.h"#include "ar531x.h"#define FACTORY_RESET 0x89ABCDEF     /* * The AR5312/AR2313 hardware supports a hardware watchdog timer. * The timer is programmed to decrement until it hits zero.  Then * it generates either SYSTEM RESET or an NMI.  In order to avoid * one of these events, software must reset the watchdog timer * before it expires. *//* * Macros to convert between "watchdog ticks" and milliseconds. * The watchdog counts down at the system frequency (1/4 CPU freq). */#define wdticks_to_ms(wdticks) (((wdticks) * 1000) / ar531x_sys_frequency())#define ms_to_wdticks(ms) (((ms) / 1000) * ar531x_sys_frequency())#define AR531X_WATCHDOG_MIN_MS 1000#define AR531X_WATCHDOG_DEFAULT_S 60#define UDELAY_COUNT 4*1000DECLARE_WAIT_QUEUE_HEAD(fact_reset_queue);static struct ar531x_boarddata *ar531x_board_configuration=NULL;static unsigned int ar531x_watchdog_timer_value = 0;static unsigned long udelay;static int ar531xwdt_is_open;static int expect_close = 0;static int margin = AR531X_WATCHDOG_DEFAULT_S; /* WDT timeout value in seconds */MODULE_PARM(margin,"i");MODULE_PARM_DESC(margin, "Watchdog timeout value");#ifdef CONFIG_WATCHDOG_NOWAYOUTstatic int nowayout = 1;#elsestatic int nowayout = 0;#endifMODULE_PARM(nowayout,"i");MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");void factory_reset_intr(int cpl, void *dev_id, struct pt_regs *regs){        udelay = UDELAY_COUNT;        while (udelay) {#ifdef CONFIG_AR531X_COBRA                if (sysRegRead(AR531XPLUS_GPIO_DI) & (1 << ar531x_board_configuration->resetConfigGpio)) {#else                if (sysRegRead(AR531X_GPIO_DI) & (1 << ar531x_board_configuration->resetConfigGpio)) {#endif                        udelay--;		}                else                        break;                udelay(1000);        }	        if (!udelay) {		wake_up(&fact_reset_queue);		}}/* * WatchDog Interface *//* * Notify the watchdog that we're alive. * Reset the watchdog timer. */voidwatchdog_notify_alive(void){#ifdef CONFIG_AR531X_COBRA	sysRegWrite(AR531XPLUS_WD, ar531x_watchdog_timer_value);#else	sysRegWrite(AR531X_WD_TIMER, ar531x_watchdog_timer_value);#endif	sysWbFlush();}/* * Start the watchdog timer. */intwatchdog_start(unsigned int milliseconds){	if (milliseconds < AR531X_WATCHDOG_MIN_MS)		return -1;	ar531x_watchdog_timer_value = ms_to_wdticks(milliseconds);	watchdog_notify_alive(); /* Initialize timer */#ifdef CONFIG_AR531X_COBRA	/*	 * Cause AHB error interrupt on watchdog expiration.	 * See bug 14407 for details.	 */	sysRegWrite(AR531XPLUS_WDC, WDC_AHB_INTR);#else	/*	 * Cause a system RESET on watchdog expiration.	 */	sysRegWrite(AR531X_WD_CTRL, AR531X_WD_CTRL_RESET);#endif    return 0;}/* * Stop the watchdog timer. */intwatchdog_stop(void){#ifdef CONFIG_AR531X_COBRA	sysRegWrite(AR531XPLUS_WD, WDC_IGNORE_EXPIRATION);#else	sysRegWrite(AR531X_WD_CTRL, AR531X_WD_CTRL_IGNORE_EXPIRATION);#endif	return 0;}/* * Kernel Methods */static ssize_tar531xwdt_read(struct file *file, char *buf, size_t count, loff_t *ppos){	return -EINVAL;}static ssize_tar531xwdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos){	/* Can't seek (pwrite) on this device */	if (ppos != &file->f_pos)		return -ESPIPE;	if (count) {		if (!nowayout) {			size_t i;			/* In case it was set long ago */			expect_close = 0;			for (i = 0; i != count; i++) {				char c;				if (get_user(c, buf + i))					return -EFAULT;				if (c == 'V')					expect_close = 1;			}		}		watchdog_notify_alive();		return 1;	}	return 0;}intae531x_get_board_config(void){    int dataFound;    char *bd_config;    /*     * Find start of Board Configuration data, using heuristics:     * Search back from the (aliased) end of flash by 0x1000 bytes     * at a time until we find the string "5311", which marks the     * start of Board Configuration.  Give up if we've searched     * more than 500KB.     */    dataFound = 0;    for (bd_config = (char *)0xbffff000;         bd_config > (char *)0xbff80000;         bd_config -= 0x1000)    {        if ( *(int *)bd_config == AR531X_BD_MAGIC) {            dataFound = 1;            break;        }    }    if (!dataFound) {        printk("Could not find Board Configuration Data\n");                bd_config = NULL;    }    ar531x_board_configuration = (struct ar531x_boarddata *) bd_config;    return(dataFound);}static intar531xwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,	  unsigned long arg){	switch(cmd) {		case FACTORY_RESET:			if (!ae531x_get_board_config())				return -EINVAL;        		if (request_irq(AR531X_GPIO_IRQ_BASE+ar531x_board_configuration->resetConfigGpio,factory_reset_intr,SA_INTERRUPT,"reset_handler",NULL)) {					return -EINVAL;        		}			sleep_on(&fact_reset_queue);	}	return 0;			}static intar531xwdt_open(struct inode *inode, struct file *file){	switch (MINOR(inode->i_rdev)) {		case WATCHDOG_MINOR:						if (ar531xwdt_is_open)				return -EBUSY;			/* Activate watchdog */			if (watchdog_start(margin * 1000) < 0)				return -EINVAL;			ar531xwdt_is_open = 1;			return 0;		default:			return -ENODEV;	}	return 0;}static intar531xwdt_close(struct inode *inode, struct file *file){	if (MINOR(inode->i_rdev) == WATCHDOG_MINOR) {		if (expect_close)			watchdog_stop();		else			printk("WDT device closed unexpectedly. WDT will not stop!\n");		ar531xwdt_is_open = 0;	}	return 0;}/* *	Notifier for system down */static intar531xwdt_notify_sys(struct notifier_block *this, unsigned long code,	void *unused){	if (code == SYS_DOWN || code == SYS_HALT) {		/* Turn the WDT off */		watchdog_stop();	}	return NOTIFY_DONE;}/* *	Kernel Interfaces */static struct file_operations ar531xwdt_fops = {	owner:		THIS_MODULE,	read:		ar531xwdt_read,	write:		ar531xwdt_write,	ioctl:		ar531xwdt_ioctl,	open:		ar531xwdt_open,	release:	ar531xwdt_close,};static struct miscdevice ar531xwdt_miscdev = {	WATCHDOG_MINOR,	"watchdog",	&ar531xwdt_fops};/* *	The WDT needs to learn about soft shutdowns in order to *	turn the watchdog registers off. */static struct notifier_block ar531xwdt_notifier = {	ar531xwdt_notify_sys,	NULL,	0};static int __initar531xwdt_init(void){	spin_lock_init(&ar531xwdt_lock);	misc_register(&ar531xwdt_miscdev);	register_reboot_notifier(&ar531xwdt_notifier);	return 0;}static void __exitar531xwdt_exit(void){	misc_deregister(&ar531xwdt_miscdev);	unregister_reboot_notifier(&ar531xwdt_notifier);}module_init(ar531xwdt_init);module_exit(ar531xwdt_exit);MODULE_AUTHOR("Atheros Communications, Inc.");MODULE_DESCRIPTION("Support for Atheros WiSoC Watchdog Timer");#ifdef MODULE_LICENSEMODULE_LICENSE("Atheros");#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -