diff -uprN linux-2.6.11-rc4.orig/arch/ppc/kernel/head_44x.S linux-2.6.11-rc4/arch/ppc/kernel/head_44x.S --- linux-2.6.11-rc4.orig/arch/ppc/kernel/head_44x.S 2005-02-22 12:59:33.000000000 +0900 +++ linux-2.6.11-rc4/arch/ppc/kernel/head_44x.S 2005-02-26 02:48:31.000000000 +0900 @@ -444,8 +444,13 @@ interrupt_base: EXCEPTION(0x1010, FixedIntervalTimer, UnknownException, EXC_XFER_EE) /* Watchdog Timer Interrupt */ - /* TODO: Add watchdog support */ +#if defined(CONFIG_PPC4xx_WATCHDOG) && !defined(CONFIG_PPC4xx_WATCHDOG_COMPAT) + CRITICAL_EXCEPTION(0x1020, WatchdogTimer, ppc4xx_wdt_interrupt) +#else CRITICAL_EXCEPTION(0x1020, WatchdogTimer, UnknownException) +#endif + + /* Data TLB Error Interrupt */ START_EXCEPTION(DataTLBError) diff -uprN linux-2.6.11-rc4.orig/arch/ppc/kernel/head_4xx.S linux-2.6.11-rc4/arch/ppc/kernel/head_4xx.S --- linux-2.6.11-rc4.orig/arch/ppc/kernel/head_4xx.S 2005-02-22 12:59:33.000000000 +0900 +++ linux-2.6.11-rc4/arch/ppc/kernel/head_4xx.S 2005-02-26 02:48:31.000000000 +0900 @@ -477,19 +477,23 @@ label: #if 0 /* NOTE: - * FIT and WDT handlers are not implemented yet. + * FIT handlers are not implemented yet. */ /* 0x1010 - Fixed Interval Timer (FIT) Exception */ STND_EXCEPTION(0x1010, FITException, UnknownException) +#endif + /* 0x1020 - Watchdog Timer (WDT) Exception */ - +#if defined(CONFIG_PPC4xx_WATCHDOG) && !defined(CONFIG_PPC4xx_WATCHDOG_COMPAT) + CRITICAL_EXCEPTION(0x1020, WDTException, ppc4xx_wdt_interrupt) +#else CRITICAL_EXCEPTION(0x1020, WDTException, UnknownException) #endif - + /* 0x1100 - Data TLB Miss Exception * As the name implies, translation is not in the MMU, so search the * page tables and fix it. The only purpose of this function is to diff -uprN linux-2.6.11-rc4.orig/arch/ppc/kernel/head_booke.h linux-2.6.11-rc4/arch/ppc/kernel/head_booke.h --- linux-2.6.11-rc4.orig/arch/ppc/kernel/head_booke.h 2005-02-22 12:59:33.000000000 +0900 +++ linux-2.6.11-rc4/arch/ppc/kernel/head_booke.h 2005-02-26 01:01:11.000000000 +0900 @@ -194,8 +194,8 @@ label: CRITICAL_EXCEPTION_PROLOG; \ addi r3,r1,STACK_FRAME_OVERHEAD; \ EXC_XFER_TEMPLATE(hdlr, n+2, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \ - NOCOPY, transfer_to_handler_full, \ - ret_from_except_full) + NOCOPY, crit_transfer_to_handler, \ + ret_from_crit_exc) #define MCHECK_EXCEPTION(n, label, hdlr) \ START_EXCEPTION(label); \ diff -uprN linux-2.6.11-rc4.orig/arch/ppc/syslib/ppc4xx_setup.c linux-2.6.11-rc4/arch/ppc/syslib/ppc4xx_setup.c --- linux-2.6.11-rc4.orig/arch/ppc/syslib/ppc4xx_setup.c 2005-02-22 12:59:33.000000000 +0900 +++ linux-2.6.11-rc4/arch/ppc/syslib/ppc4xx_setup.c 2005-02-26 01:01:15.000000000 +0900 @@ -48,9 +48,11 @@ extern void abort(void); extern void ppc4xx_find_bridges(void); +#ifdef CONFIG_PPC4xx_WATCHDOG extern void ppc4xx_wdt_heartbeat(void); extern int wdt_enable; extern unsigned long wdt_period; +#endif /* CONFIG_PPC4xx_WATCHDOG */ /* Global Variables */ bd_t __res; @@ -257,7 +259,7 @@ ppc4xx_init(unsigned long r3, unsigned l *(char *) (r7 + KERNELBASE) = 0; strcpy(cmd_line, (char *) (r6 + KERNELBASE)); } -#if defined(CONFIG_PPC405_WDT) +#ifdef CONFIG_PPC4xx_WATCHDOG /* Look for wdt= option on command line */ if (strstr(cmd_line, "wdt=")) { int valid_wdt = 0; @@ -272,7 +274,7 @@ ppc4xx_init(unsigned long r3, unsigned l } wdt_enable = valid_wdt; } -#endif +#endif /* CONFIG_PPC4xx_WATCHDOG */ /* Initialize machine-dependent vectors */ @@ -287,9 +289,9 @@ ppc4xx_init(unsigned long r3, unsigned l ppc_md.calibrate_decr = ppc4xx_calibrate_decr; -#ifdef CONFIG_PPC405_WDT +#ifdef CONFIG_PPC4xx_WATCHDOG_COMPAT ppc_md.heartbeat = ppc4xx_wdt_heartbeat; -#endif +#endif /* CONFIG_PPC4xx_WATCHDOG */ ppc_md.heartbeat_count = 0; ppc_md.find_end_of_memory = ppc4xx_find_end_of_memory; diff -uprN linux-2.6.11-rc4.orig/drivers/char/watchdog/Kconfig linux-2.6.11-rc4/drivers/char/watchdog/Kconfig --- linux-2.6.11-rc4.orig/drivers/char/watchdog/Kconfig 2005-02-22 12:58:29.000000000 +0900 +++ linux-2.6.11-rc4/drivers/char/watchdog/Kconfig 2005-02-26 02:48:42.000000000 +0900 @@ -346,6 +346,25 @@ config 8xx_WDT tristate "MPC8xx Watchdog Timer" depends on WATCHDOG && 8xx +config PPC4xx_WATCHDOG + bool "Watchdog on PowerPC 4xx series" + depends on WATCHDOG && 4xx + ---help--- + This is the driver for the hardware watchdog timers present on + PowerPC 4xx series(PPC405GP/GPr,PPC440GP/GX). +config PPC4xx_WATCHDOG_COMPAT + bool "Enable Compatibility with old ppc405 driver." + depends on PPC4xx_WATCHDOG + ---help--- + If you want send acks to WDT with timer interrupt, turn on this + option. + + This option changes behaviors of the driver to old ppc405 software + watch dog driver did. Strictly speaking, it may not have the + complete compatibility with ppc405 software WDT. It does not + use WDT exception in PowerPC 4xx. + + # MIPS Architecture config INDYDOG diff -uprN linux-2.6.11-rc4.orig/drivers/char/watchdog/Makefile linux-2.6.11-rc4/drivers/char/watchdog/Makefile --- linux-2.6.11-rc4.orig/drivers/char/watchdog/Makefile 2005-02-22 12:58:30.000000000 +0900 +++ linux-2.6.11-rc4/drivers/char/watchdog/Makefile 2005-02-26 01:01:20.000000000 +0900 @@ -39,3 +39,4 @@ obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb. obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o +obj-$(CONFIG_PPC4xx_WATCHDOG) += ppc4xx_wdt.o \ No newline at end of file diff -uprN linux-2.6.11-rc4.orig/drivers/char/watchdog/ppc4xx_wdt.c linux-2.6.11-rc4/drivers/char/watchdog/ppc4xx_wdt.c --- linux-2.6.11-rc4.orig/drivers/char/watchdog/ppc4xx_wdt.c 1970-01-01 09:00:00.000000000 +0900 +++ linux-2.6.11-rc4/drivers/char/watchdog/ppc4xx_wdt.c 2005-02-26 02:48:42.000000000 +0900 @@ -0,0 +1,717 @@ +/* + * + * Copyright (c) 2004 Fujitsu Limited + * + * Module name: ppc4xx_wdt.c + * Author: Takeharu KATO + * Description: + * Watchdog driver for PowerPC 4xx-based processors. + * Derived from drivers/char/watchdog/wdt.c by Alan cox + * and drivers/char/watchdog/ppc405_wdt.c by Armin Kuster. + * + * PPC4xx WDT operation is driverd from Appendix of + * PowerPC Embedded Processors Application Note + * ``PowerPC 40x Watch Dog Timer'' published from IBM. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(CONFIG_440GP) +#include +#endif /* CONFIG_440GP */ +#if defined(CONFIG_440GX) +#include +#endif /* CONFIG_440GX */ +#include "ppc4xx_wdt.h" + +/* micro seconds per one milli-second(used to calculatewatchdog + * counter to be set. */ +#define US_PER_MS 1000 +/* MHz in Hz */ +#define MHZ 1000000 +/* + * External linkage + */ +int wdt_enable=0; /* WDT start on boot */ +int wdt_period = WD_TIMO; /* Time out in ms(see: ppc4xx_wdt.h) */ +/* + * Global variables + */ +static int wdt_count = 0; /* WDT intrrupt counter to be reloaded */ +static volatile int wdt_heartbeat_count = 0; /* WDT intrrupt counter(compatible mode)*/ +static unsigned long driver_state; /* Driver status (see: ppc4xx_wdt.h) */ +void ppc4xx_wdt_heartbeat(void); +/* + * Internal linkage functions + */ +static __inline__ void __ppc4xx_wdt_setup_val(int period,int reset); +static __inline__ void __ppc4xx_wdt_enable(void); +static __inline__ void __ppc4xx_wdt_disable(void); +static __inline__ int __ppc4xx_wdt_is_enabled(void); +static __inline__ void __ppc4xx_wdt_clear_int_stat(void); +static __inline__ void __ppc4xx_wdt_set_timeout(int t); +#if !defined(CONFIG_PPC4xx_WATCHDOG_COMPAT) +static unsigned long cpu_clock=0; /* To store cpu_clock */ +#if defined(CONFIG_40x) +static __inline__ int __ppc40x_get_cpu_clock(void); +#endif /* CONFIG_40x */ +#if defined(CONFIG_44x) +static __inline__ int __ppc44x_get_cpu_clock(void); +#endif /* CONFIG_44x */ +static __inline__ void __ppc4xx_get_cpu_clock(void); +#endif /* CONFIG_PPC4xx_WATCHDOG_COMPAT */ +static __inline__ void ppc4xx_wdt_init_device(void); +static __inline__ int ppc4xx_wdt_is_enabled(void); +static __inline__ int ppc4xx_wdt_start(void); +static __inline__ int ppc4xx_wdt_stop(void); +static __inline__ int ppc4xx_wdt_ping(void); +static __inline__ int ppc4xx_wdt_set_timeout(int t); +static __inline__ int ppc4xx_wdt_get_status(int *status); +static ssize_t ppc4xx_wdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos); +static int ppc4xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,unsigned long arg); +static int ppc4xx_wdt_open(struct inode *inode, struct file *file); +static int ppc4xx_wdt_release(struct inode *inode, struct file *file); +static int ppc4xx_wdt_notify_sys(struct notifier_block *this, unsigned long code,void *unused); +static int __init ppc4xx_wdt_init(void); +static void __exit ppc4xx_wdt_exit(void); + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +/* + * Watchdog operations on PPC4xx MPU + */ +#if !defined(CONFIG_PPC4xx_WATCHDOG_COMPAT) +#if defined(CONFIG_40x) +/** + * __ppc40x_get_cpu_clock + * Get CPU clock of PPC405 family + */ +static __inline__ int +__ppc40x_get_cpu_clock(void) +{ + bd_t *bip = &__res; + + return (bip->bi_tbfreq); +} +#endif /* CONFIG_40x */ + +#if defined(CONFIG_44x) +/** + * ppc44x_get_cpu_clock + * Get CPU clock of PPC440 family + */ +static __inline__ int +__ppc44x_get_cpu_clock(void) +{ + struct ibm44x_clocks clocks; + + /* Note: + * Following functions are assigned in init section. + * So we keep cpu_clocks in this module. + */ +#if defined(CONFIG_440GX) + ibm440gx_get_clocks(&clocks, 33333333, 6 * 1843200); +#else +#if defined(CONFIG_440GP) + ibm440gp_get_clocks(&clocks, 33333333, 6 * 1843200); +#endif +#endif + + return clocks.cpu; +} +#endif /* CONFIG_44x */ +#endif /* !CONFIG_PPC4xx_WATCHDOG_COMPAT */ +/** + * ppc4xx_get_cpu_clock + * Get CPU clock of PPC4xx family + */ +#if !defined(CONFIG_PPC4xx_WATCHDOG_COMPAT) +static __inline__ void +__ppc4xx_get_cpu_clock(void) +{ + if (!cpu_clock) +#if defined(CONFIG_40x) + cpu_clock = __ppc40x_get_cpu_clock(); +#else +#if defined(CONFIG_44x) + cpu_clock = __ppc44x_get_cpu_clock(); +#else +#error "PPC4xx WDT Detect invalid configuration(Unknown CPU)" +#endif /* CONFIG_44x */ +#endif /* CONFIG_40x */ + return; +} +#else +#define __ppc4xx_get_cpu_clock() do{}while(0) +#endif /* CONFIG_PPC4xx_WATCHDOG_COMPAT */ +/** + * __ppc4xx_wdt_setup_val + * Enable 4xx Watchdog, sets up passed in values for TCR[WP], + * TCR[WRC] + * + * @period: Input Watchdog Period - TCR[WP] + * 0 = 2^17 clocks + * 1 = 2^21 clocks + * 2 = 2^25 clocks + * 3 = 2^29 clocks + * @reset: Watchdog reset control - TCR[WRC] + * 0 = No reset + * 1 = PPC Core reset only + * 2 = PPC Chip reset + * 3 = System reset + * Note: The meaning of period number is differ PPC440GP from PPC440GX. + */ +static __inline__ void +__ppc4xx_wdt_setup_val(int period,int reset) +{ + unsigned long val; + + /* Set up TCR */ + val=period< 1. In other word, Time Base bit tansition + * 1 -> 0 does not cause the exception. The is the reason why the divisor + * as follows should be multiplied by 2. + */ + div=( (WDT_CLK_PER_INT_WP_VAL/(cpu_clock/MHZ)) * 2); + ppc4xx_wdt_dbg("div : %lu\n",div); + tmp /= div; + wdt_count=tmp; +#else + wdt_count=t; /* Assume 1ms tick */ +#endif + return; +} +/* + * Driver specific functions + */ +/** + * ppc4xx_wdt_heartbeat: + * Ping routine called from kernel. + */ +void +ppc4xx_wdt_heartbeat(void) +{ + /* Disable watchdog */ + __ppc4xx_wdt_disable(); + + /* Write a watchdog value */ + __ppc4xx_wdt_clear_int_stat(); + + if (!wdt_enable) + goto out; + +#if defined(CONFIG_PPC4xx_WATCHDOG_COMPAT) + if (wdt_heartbeat_count > 0) + wdt_heartbeat_count--; + else + panic(ppc4xx_mkmsg("Initiating system reboot.\n")); +#endif /* CONFIG_PPC4xx_WATCHDOG_COMPAT */ + /* Enable watchdog */ + __ppc4xx_wdt_enable(); + out: + /* Reset count */ + ppc_md.heartbeat_count = 0; +} +/** + * ppc4xx_wdt_interrupt: + * Watchdog interrupt handler. + */ +void +ppc4xx_wdt_interrupt(struct pt_regs *regs) +{ + unsigned long status=mfspr(SPRN_TSR); + unsigned long flags; + + if (status & (TSR_WIS|TSR_ENW)){ + /* Disable watchdog */ + __ppc4xx_wdt_disable(); + + __ppc4xx_wdt_clear_int_stat(); + local_irq_save(flags); +#if !defined(CONFIG_PPC4xx_WATCHDOG_COMPAT) + if (wdt_heartbeat_count) { + --wdt_heartbeat_count; + } else { +#ifdef ONLY_TESTING + ppc4xx_wdt_crit("Would Reboot by application failure.\n"); +#else +#ifdef SOFTWARE_REBOOT + ppc4xx_wdt_crit("Initiating system reboot.\n"); + machine_restart(NULL); +#else + panic(ppc4xx_mkmsg("Initiating system reboot.\n")); +#endif /* SOFTWARE_REBOOT */ +#endif /* ONLY_TESTING */ + } /* Time out */ +#endif /* !CONFIG_PPC4xx_WATCHDOG_COMPAT */ + local_irq_restore(flags); + /* Enable watchdog */ + __ppc4xx_wdt_enable(); + } + return; +} + +/* + * Driver Logic functions + */ +static __inline__ int +ppc4xx_wdt_is_enabled(void) +{ + return __ppc4xx_wdt_is_enabled(); +} +/** + * ppc4xx_wdt_start: + * + * Start the watchdog driver. + */ +static __inline__ int +ppc4xx_wdt_start(void) +{ + __ppc4xx_wdt_enable(); + return 0; +} + +/** + * ppc4xx_wdt_stop: + * + * Stop the watchdog driver. + */ +static __inline__ int +ppc4xx_wdt_stop (void) +{ + __ppc4xx_wdt_disable(); + return 0; +} +/** + * ppc4xx_wdt_ping: + * + * Reload counter one with the watchdog heartbeat. We don't bother reloading + * the cascade counter. + */ +static __inline__ int +ppc4xx_wdt_ping(void) +{ + /* Disable watchdog */ + __ppc4xx_wdt_disable(); + /* Write a watchdog value */ + __ppc4xx_wdt_clear_int_stat(); + /* Reset count */ + wdt_heartbeat_count=wdt_count; + /* Enable watchdog */ + __ppc4xx_wdt_enable(); + + return 0; +} +/** + * ppc4xx_wdt_set_timeout: + * @t: the new timeout value that needs to be set. + * + * Set a new time out value for the watchdog device. + * If the heartbeat value is incorrect we keep the old value + * and return -EINVAL. If successfull we + * return 0. + */ +static __inline__ int +ppc4xx_wdt_set_timeout(int t) +{ + if ((t < WDT_HEARTBEAT_MIN) || (t > WDT_HEARTBEAT_MAX)) + return -EINVAL; + + wdt_period = t; + __ppc4xx_wdt_set_timeout(t); + wdt_heartbeat_count=wdt_count; + ppc4xx_wdt_dbg("The WDT counter set %d.\n",wdt_count); + + return 0; +} + +/** + * ppc4xx_wdt_get_status: + * @status: the new status. + * + * Return the enable/disable card status. + */ +static __inline__ int +ppc4xx_wdt_get_status(int *status) +{ + if (wdt_enable) + *status = WDIOS_ENABLECARD; + else + *status = WDIOS_DISABLECARD; + + return 0; +} +/* + * Kernel Interfaces + */ +/** + * ppc4xx_wdt_init_device: + * + * Initilize PowerPC 4xx family Watch Dog facility. + */ +static void +ppc4xx_wdt_init_device(void) +{ + __ppc4xx_get_cpu_clock(); + __ppc4xx_wdt_setup_val(WDT_WP,WDT_RESET_NONE); +} +/** + * ppc4xx_wdt_write: + * @file: file handle to the watchdog + * @buf: buffer to write (unused as data does not matter here + * @count: count of bytes + * @ppos: pointer to the position to write. No seeks allowed + * + * A write to a watchdog device is defined as a keepalive signal. Any + * write of data will do, as we we don't define content meaning expept + * 'V' character. It is performed as a sign to set stop-on-close mode. + */ + +static ssize_t +ppc4xx_wdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +{ + size_t i; + + if (!nowayout) { + /* In case it was set long ago */ + clear_bit(WDT_STATE_STOP_ON_CLOSE, &driver_state); + + for (i = 0; i < count; i++) { + char c; + + if (get_user(c, buf + i)) + return -EFAULT; + + if (c == 'V') { + set_bit(WDT_STATE_STOP_ON_CLOSE, &driver_state); + } + } + } + ppc4xx_wdt_ping(); + + return count; +} +static struct watchdog_info ident = { + .options=WDIOF_SETTIMEOUT|WDIOF_KEEPALIVEPING|WDIOF_MAGICCLOSE, + .firmware_version = 1, + .identity = "PPC4xx WDT", +}; + +/** + * ppc4xx_wdt_ioctl: + * @inode: inode of the device + * @file: file handle to the device + * @cmd: watchdog command + * @arg: argument pointer + * + */ +static int +ppc4xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + int new_timeout; + int status; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; /* It may be too strict manner. */ + switch(cmd) + { + default: + return -ENOIOCTLCMD; + case WDIOC_GETSUPPORT: + if (copy_to_user((struct watchdog_info *)arg, &ident, sizeof(struct watchdog_info))) + return -EFAULT; + else + break; + case WDIOC_GETSTATUS: + ppc4xx_wdt_get_status(&status); + return put_user(status,(int *)arg); + case WDIOC_KEEPALIVE: + ppc4xx_wdt_ping(); + break; + case WDIOC_SETTIMEOUT: + if (get_user(new_timeout, (int *)arg)) + return -EFAULT; + if (ppc4xx_wdt_set_timeout(new_timeout)) + return -EINVAL; + ppc4xx_wdt_ping(); + break; + case WDIOC_GETTIMEOUT: + return put_user(wdt_period, (int *)arg); + case WDIOC_SETOPTIONS: + if (get_user(status, (int *)arg)) + return -EFAULT; + /* Return -EINVAL when the driver can not figure out + * what it should do. Unknown cases are just ignored. + */ + if ( (status & (WDIOS_DISABLECARD|WDIOS_ENABLECARD)) + == (WDIOS_DISABLECARD|WDIOS_ENABLECARD) ) + return -EINVAL; + if (status & WDIOS_DISABLECARD) { + wdt_enable = 0; + ppc4xx_wdt_stop(); + ppc4xx_wdt_note("Watchdog timer is disabled\n"); + } + if (status & WDIOS_ENABLECARD) { + wdt_enable = 1; + ppc4xx_wdt_start(); + ppc4xx_wdt_note("Watchdog timer is enabled\n"); + } + break; + } + return 0; +} +/** + * ppc4xx_wdt_open: + * @inode: inode of device + * @file: file handle to device + * + * The watchdog device has been opened. The watchdog device is single + * open and start the WDT timer. + */ +static int +ppc4xx_wdt_open(struct inode *inode, struct file *file) +{ + if (test_and_set_bit(WDT_STATE_OPEN, &driver_state)) + return -EBUSY; + /* + * Activate + */ + ppc4xx_wdt_start(); + wdt_enable=1; + + if (nowayout) + set_bit(WDT_STATE_STOP_ON_CLOSE, &driver_state); + + return 0; +} + +/** + * ppc4xx_wdt_release: + * @inode: inode to board + * @file: file handle to board + * + */ +static int +ppc4xx_wdt_release(struct inode *inode, struct file *file) +{ + if (test_bit(WDT_STATE_STOP_ON_CLOSE, &driver_state)) { + ppc4xx_wdt_note("WDT device is stopped.\n"); + ppc4xx_wdt_stop(); + wdt_enable=0; + } else { + if ( (ppc4xx_wdt_is_enabled()) && (!nowayout) ) { + ppc4xx_wdt_note("WDT device may be closed unexpectedly. WDT will not stop!\n"); + ppc4xx_wdt_ping(); + } + } + clear_bit(WDT_STATE_OPEN, &driver_state); + + return 0; +} +/** + * notify_sys: + * @this: our notifier block + * @code: the event being reported + * @unused: unused + * + */ + +static int +ppc4xx_wdt_notify_sys(struct notifier_block *this, unsigned long code, + void *unused) +{ + if(code==SYS_DOWN || code==SYS_HALT) { + /* Turn the card off */ + ppc4xx_wdt_stop(); + } + return NOTIFY_DONE; +} + +static struct file_operations ppc4xx_wdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = ppc4xx_wdt_write, + .ioctl = ppc4xx_wdt_ioctl, + .open = ppc4xx_wdt_open, + .release = ppc4xx_wdt_release, +}; + +static struct miscdevice ppc4xx_wdt_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &ppc4xx_wdt_fops, +}; + +/* + * The WDT card needs to know about shutdowns in order to + * turn WDT off. + */ + +static struct notifier_block ppc4xx_wdt_notifier = { + .notifier_call = ppc4xx_wdt_notify_sys, +}; + +/** + * cleanup_module: + * + * If your watchdog is set to continue ticking on close and you unload + * it, well it keeps ticking. You just have to load a new + * module in 60 seconds or reboot. + * This behavior(more over the comments as above) is borrowed from + * Alan cox's driver. + */ + +static void __exit +ppc4xx_wdt_exit(void) +{ + misc_deregister(&ppc4xx_wdt_miscdev); + unregister_reboot_notifier(&ppc4xx_wdt_notifier); +} + +/** + * ppc4xx_wdt_init: + * + * Set up the WDT relevant timer facility. + */ + +static int __init +ppc4xx_wdt_init(void) +{ + int ret; + + ret = register_reboot_notifier(&ppc4xx_wdt_notifier); + if(ret) { + ppc4xx_wdt_err("Cannot register reboot notifier (err=%d)\n", ret); + return ret; + } + + ret = 0; + ppc4xx_wdt_init_device(); + /* Check that the heartbeat value is within it's range ; if not reset to the default */ + if (ppc4xx_wdt_set_timeout(wdt_period)) { + ppc4xx_wdt_set_timeout(WD_TIMO); + ppc4xx_wdt_info("The heartbeat value must be 0 + * Description: + * Header file for PPC4xx watchdog driver. + */ +#ifndef _ARCH_PPC_SYSLIB_PPC4XX_WDT_H +#define _ARCH_PPC_SYSLIB_PPC4XX_WDT_H +#include +#include +#include +#include + +/* + * Driver behavior flags(bit position) + */ +#define WDT_STATE_OPEN 0 /* driver is opend */ +#define WDT_STATE_STOP_ON_CLOSE 1 /* Stop with close is expected */ +#define WDT_STATE_COMPAT_MODE 2 /* Monta Vista Linux Comaptible */ +/* + * For comaptible mode + */ +#define WDIOC_GETPERIOD WDIOC_GETTIMEOUT +#define WDIOC_SETPERIOD WDIOC_SETTIMEOUT +/* + * Configurations + */ +#define WD_TIMO 60000 /* Default timeout = 60000 ms(1min) */ +#define WDT_HEARTBEAT_MIN 100 /* Minimum timeout = 100 ms */ +#define WDT_HEARTBEAT_MAX 600000 /* Maximum timeout = 600000ms(1hour) */ +#ifdef __KERNEL__ +//#define WDT_DEBUG /* Debug switch */ +/* + * Reset type + */ +#define WDT_RESET_NONE 0 +#define WDT_RESET_CORE 1 +#define WDT_RESET_CHIP 2 +#define WDT_RESET_SYS 3 +/* + * Bit positions in TCR register on PPC4xx series. + */ +#define WDT_TCR_WP_BIT 1 /* WP bit in TCR (bit[0..1]) */ +#define WDT_TCR_WRC_BIT 3 /* WRC bit in TCR (bit[2..3]) */ +#define WDT_TCR_WIE_BIT 4 /* WIE bit in TCR (bit[4]) */ +/* + * TCR[WP] relevant definitions + */ +#define WDT_TCR_WP_SHIFT (31 - WDT_TCR_WP_BIT) +#define WDT_TCR_WRC_SHIFT (31 - WDT_TCR_WRC_BIT) +#define WDT_TCR_WIE_SHIFT (31 - WDT_TCR_WIE_BIT) +#define WDT_TCR_WDT_ENABLE (1<