1、使用示例:
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
#include <linux/timer.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/fs.h>
#include <linux/notifier.h>
#include <linux/reboot.h>
#include <linux/init.h>
#include <asm/uaccess.h>
#include <asm/io.h>
//#include <asm/arch/hardware.h>
#include <linux/kthread.h>
//#include <asm/arch/clock.h>
#include <linux/string.h>
#include <linux/sched.h>
#define OSDRV_MODULE_VERSION_STRING "HISI_WDT-MDC030001 @Hi3518v100"
#define HISILICON_SCTL_BASE 0x20050000
/* define watchdog IO */
#define HIWDT_BASE 0x20040000
#define HIWDT_REG(x) (HIWDT_BASE + (x))
#define HIWDT_LOAD 0x000
#define HIWDT_VALUE 0x004
#define HIWDT_CTRL 0x008
#define HIWDT_INTCLR 0x00C
#define HIWDT_RIS 0x010
#define HIWDT_MIS 0x014
#define HIWDT_LOCK 0xC00
#define HIWDT_UNLOCK_VAL 0x1ACCE551
void __iomem *reg_ctl_base_va;
void __iomem *reg_wdt_base_va;
#define IO_WDT_ADDRESS(x) (reg_wdt_base_va + ((x)-(HIWDT_BASE)))
#define hiwdt_readl(x) readl(IO_WDT_ADDRESS(HIWDT_REG(x)))
#define hiwdt_writel(v,x) writel(v, IO_WDT_ADDRESS(HIWDT_REG(x)))
/* debug */
#define HIDOG_PFX "HiDog: "
#define hidog_dbg(params...) printk(KERN_INFO HIDOG_PFX params)
/* module param */
#define HIDOG_TIMER_MARGIN 60
static int default_margin = HIDOG_TIMER_MARGIN; /* in seconds */
#define HIDOG_TIMER_DEMULTIPLY 9
module_param(default_margin, int, 0);
MODULE_PARM_DESC(default_margin, "Watchdog default_margin in seconds. (0<default_margin<80, default=" __MODULE_STRING(HIDOG_TIMER_MARGIN) ")");
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
static int nodeamon = 0;
module_param(nodeamon, int, 0);
MODULE_PARM_DESC(nodeamon, "By default, a kernel deamon feed watchdog when idle, set 'nodeamon=1' to disable this. (default=0)");
/* watchdog info */
static struct watchdog_info ident = {
.options = WDIOF_SETTIMEOUT |
WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE,
.firmware_version = 0,
.identity = "Hisilicon Watchdog",
};
/* local var */
static DEFINE_SPINLOCK(hidog_lock);
static int cur_margin = HIDOG_TIMER_MARGIN;
//static pid_t pid_hidog_deamon = -1;
struct task_struct *task_hidog_deamon = NULL;
#define HIDOG_EXIT 0
#define HIDOG_SELFCLR 1
#define HIDOG_EXTCLR 2
volatile static unsigned int hidog_state = 0;
static unsigned long driver_open = 0, orphan_timer = 0;
static int options = WDIOS_ENABLECARD;
#ifndef MHZ
#define MHZ (1000*1000)
#endif
static unsigned long rate = 3*MHZ;
static inline void hidog_set_timeout(unsigned int nr)
{
unsigned long cnt = (~0x0)/rate; /* max cnt */
unsigned long flags;
spin_lock_irqsave(&hidog_lock, flags);
if( nr==0 || nr>cnt)
cnt=~0x0;
else
cnt = nr*rate;
/* unlock watchdog registers */
hiwdt_writel(HIWDT_UNLOCK_VAL, HIWDT_LOCK);
hiwdt_writel(cnt, HIWDT_LOAD);
hiwdt_writel(cnt, HIWDT_VALUE);
/* lock watchdog registers */
hiwdt_writel(0, HIWDT_LOCK);
spin_unlock_irqrestore(&hidog_lock, flags);
};
static inline void hidog_feed(void)
{
unsigned long flags;
spin_lock_irqsave(&hidog_lock, flags);
/* unlock watchdog registers */
hiwdt_writel(HIWDT_UNLOCK_VAL, HIWDT_LOCK);
/* clear watchdog */
hiwdt_writel(0x00, HIWDT_INTCLR);
/* lock watchdog registers */
hiwdt_writel(0, HIWDT_LOCK);
spin_unlock_irqrestore(&hidog_lock, flags);
};
static int hidog_set_heartbeat(int t)
{
int ret = 0;
unsigned int cnt = (~0x0)/rate;
if( t==0 ) {
printk(KERN_ERR HIDOG_PFX "set heartbeat to 0, heartbeat will not be changed.\n");
t = cur_margin;
ret = 1;
} else if( t>cnt ) {
printk(KERN_ERR HIDOG_PFX "set heartbeat range error, t = %d\n", t);
printk(KERN_ERR HIDOG_PFX "force heartbeat to %d\n", cnt);
t = cnt;
ret = -1;
}
cur_margin = t;
hidog_set_timeout(t);
hidog_feed();
if(NULL != task_hidog_deamon)
wake_up_process(task_hidog_deamon);
return ret;
}
static int hidog_keepalive(void)
{
hidog_feed();
return 0;
}
自旋锁详解:
自旋锁与互斥锁有点类似,只是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,"自旋"一词就是因此而得名。