Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 62630
b: refs/heads/master
c: 70c14ff
h: refs/heads/master
v: v3
  • Loading branch information
Dan Williams authored and Russell King committed Jul 20, 2007
1 parent d24c86b commit bfb7b1b
Show file tree
Hide file tree
Showing 8 changed files with 366 additions and 33 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 7dea1b20066cd30fb54da7e686b16b5e38b46b2d
refs/heads/master: 70c14ff0e9f5e1f5456587b827620e636ba70a09
8 changes: 8 additions & 0 deletions trunk/arch/arm/plat-iop/time.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,21 @@ static struct irqaction iop_timer_irq = {
.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
};

static unsigned long iop_tick_rate;
unsigned long get_iop_tick_rate(void)
{
return iop_tick_rate;
}
EXPORT_SYMBOL(get_iop_tick_rate);

void __init iop_init_time(unsigned long tick_rate)
{
u32 timer_ctl;

ticks_per_jiffy = (tick_rate + HZ/2) / HZ;
ticks_per_usec = tick_rate / 1000000;
next_jiffy_time = 0xffffffff;
iop_tick_rate = tick_rate;

timer_ctl = IOP_TMR_EN | IOP_TMR_PRIVILEGED |
IOP_TMR_RELOAD | IOP_TMR_RATIO_1_1;
Expand Down
16 changes: 16 additions & 0 deletions trunk/drivers/char/watchdog/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,22 @@ config PNX4008_WATCHDOG

Say N if you are unsure.

config IOP_WATCHDOG
tristate "IOP Watchdog"
depends on WATCHDOG && PLAT_IOP
select WATCHDOG_NOWAYOUT if (ARCH_IOP32X || ARCH_IOP33X)
help
Say Y here if to include support for the watchdog timer
in the Intel IOP3XX & IOP13XX I/O Processors. This driver can
be built as a module by choosing M. The module will
be called iop_wdt.

Note: The IOP13XX watchdog does an Internal Bus Reset which will
affect both cores and the peripherals of the IOP. The ATU-X
and/or ATUe configuration registers will remain intact, but if
operating as an Root Complex and/or Central Resource, the PCI-X
and/or PCIe busses will also be reset. THIS IS A VERY BIG HAMMER.

# AVR32 Architecture

config AT32AP700X_WDT
Expand Down
1 change: 1 addition & 0 deletions trunk/drivers/char/watchdog/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o
obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o
obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o
obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o
obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o

# AVR32 Architecture
obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
Expand Down
262 changes: 262 additions & 0 deletions trunk/drivers/char/watchdog/iop_wdt.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,262 @@
/*
* drivers/char/watchdog/iop_wdt.c
*
* WDT driver for Intel I/O Processors
* Copyright (C) 2005, Intel Corporation.
*
* Based on ixp4xx driver, Copyright 2004 (c) MontaVista, Software, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307 USA.
*
* Curt E Bruns <curt.e.bruns@intel.com>
* Peter Milne <peter.milne@d-tacq.com>
* Dan Williams <dan.j.williams@intel.com>
*/

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/uaccess.h>
#include <asm/hardware.h>

static int nowayout = WATCHDOG_NOWAYOUT;
static unsigned long wdt_status;
static unsigned long boot_status;

#define WDT_IN_USE 0
#define WDT_OK_TO_CLOSE 1
#define WDT_ENABLED 2

static unsigned long iop_watchdog_timeout(void)
{
return (0xffffffffUL / get_iop_tick_rate());
}

/**
* wdt_supports_disable - determine if we are accessing a iop13xx watchdog
* or iop3xx by whether it has a disable command
*/
static int wdt_supports_disable(void)
{
int can_disable;

if (IOP_WDTCR_EN_ARM != IOP_WDTCR_DIS_ARM)
can_disable = 1;
else
can_disable = 0;

return can_disable;
}

static void wdt_enable(void)
{
/* Arm and enable the Timer to starting counting down from 0xFFFF.FFFF
* Takes approx. 10.7s to timeout
*/
write_wdtcr(IOP_WDTCR_EN_ARM);
write_wdtcr(IOP_WDTCR_EN);
}

/* returns 0 if the timer was successfully disabled */
static int wdt_disable(void)
{
/* Stop Counting */
if (wdt_supports_disable()) {
write_wdtcr(IOP_WDTCR_DIS_ARM);
write_wdtcr(IOP_WDTCR_DIS);
clear_bit(WDT_ENABLED, &wdt_status);
printk(KERN_INFO "WATCHDOG: Disabled\n");
return 0;
} else
return 1;
}

static int iop_wdt_open(struct inode *inode, struct file *file)
{
if (test_and_set_bit(WDT_IN_USE, &wdt_status))
return -EBUSY;

clear_bit(WDT_OK_TO_CLOSE, &wdt_status);

wdt_enable();

set_bit(WDT_ENABLED, &wdt_status);

return nonseekable_open(inode, file);
}

static ssize_t
iop_wdt_write(struct file *file, const char *data, size_t len,
loff_t *ppos)
{
if (len) {
if (!nowayout) {
size_t i;

clear_bit(WDT_OK_TO_CLOSE, &wdt_status);

for (i = 0; i != len; i++) {
char c;

if (get_user(c, data + i))
return -EFAULT;
if (c == 'V')
set_bit(WDT_OK_TO_CLOSE, &wdt_status);
}
}
wdt_enable();
}

return len;
}

static struct watchdog_info ident = {
.options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
.identity = "iop watchdog",
};

static int
iop_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
{
int options;
int ret = -ENOTTY;

switch (cmd) {
case WDIOC_GETSUPPORT:
if (copy_to_user
((struct watchdog_info *)arg, &ident, sizeof ident))
ret = -EFAULT;
else
ret = 0;
break;

case WDIOC_GETSTATUS:
ret = put_user(0, (int *)arg);
break;

case WDIOC_GETBOOTSTATUS:
ret = put_user(boot_status, (int *)arg);
break;

case WDIOC_GETTIMEOUT:
ret = put_user(iop_watchdog_timeout(), (int *)arg);
break;

case WDIOC_KEEPALIVE:
wdt_enable();
ret = 0;
break;

case WDIOC_SETOPTIONS:
if (get_user(options, (int *)arg))
return -EFAULT;

if (options & WDIOS_DISABLECARD) {
if (!nowayout) {
if (wdt_disable() == 0) {
set_bit(WDT_OK_TO_CLOSE, &wdt_status);
ret = 0;
} else
ret = -ENXIO;
} else
ret = 0;
}

if (options & WDIOS_ENABLECARD) {
wdt_enable();
ret = 0;
}
break;
}

return ret;
}

static int iop_wdt_release(struct inode *inode, struct file *file)
{
int state = 1;
if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
if (test_bit(WDT_ENABLED, &wdt_status))
state = wdt_disable();

/* if the timer is not disbaled reload and notify that we are still
* going down
*/
if (state != 0) {
wdt_enable();
printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
"reset in %lu seconds\n", iop_watchdog_timeout());
}

clear_bit(WDT_IN_USE, &wdt_status);
clear_bit(WDT_OK_TO_CLOSE, &wdt_status);

return 0;
}

static const struct file_operations iop_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = iop_wdt_write,
.ioctl = iop_wdt_ioctl,
.open = iop_wdt_open,
.release = iop_wdt_release,
};

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

static int __init iop_wdt_init(void)
{
int ret;

ret = misc_register(&iop_wdt_miscdev);
if (ret == 0)
printk("iop watchdog timer: timeout %lu sec\n",
iop_watchdog_timeout());

/* check if the reset was caused by the watchdog timer */
boot_status = (read_rcsr() & IOP_RCSR_WDT) ? WDIOF_CARDRESET : 0;

/* Configure Watchdog Timeout to cause an Internal Bus (IB) Reset
* NOTE: An IB Reset will Reset both cores in the IOP342
*/
write_wdtsr(IOP13XX_WDTCR_IB_RESET);

return ret;
}

static void __exit iop_wdt_exit(void)
{
misc_deregister(&iop_wdt_miscdev);
}

module_init(iop_wdt_init);
module_exit(iop_wdt_exit);

module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");

MODULE_AUTHOR("Curt E Bruns <curt.e.bruns@intel.com>");
MODULE_DESCRIPTION("iop watchdog timer driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
43 changes: 43 additions & 0 deletions trunk/include/asm-arm/arch-iop13xx/iop13xx.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,39 @@ static inline int iop13xx_cpu_id(void)
return id;
}

/* WDTCR CP6 R7 Page 9 */
static inline u32 read_wdtcr(void)
{
u32 val;
asm volatile("mrc p6, 0, %0, c7, c9, 0":"=r" (val));
return val;
}
static inline void write_wdtcr(u32 val)
{
asm volatile("mcr p6, 0, %0, c7, c9, 0"::"r" (val));
}

/* WDTSR CP6 R8 Page 9 */
static inline u32 read_wdtsr(void)
{
u32 val;
asm volatile("mrc p6, 0, %0, c8, c9, 0":"=r" (val));
return val;
}
static inline void write_wdtsr(u32 val)
{
asm volatile("mcr p6, 0, %0, c8, c9, 0"::"r" (val));
}

/* RCSR - Reset Cause Status Register */
static inline u32 read_rcsr(void)
{
u32 val;
asm volatile("mrc p6, 0, %0, c0, c1, 0":"=r" (val));
return val;
}

extern unsigned long get_iop_tick_rate(void);
#endif

/*
Expand Down Expand Up @@ -480,4 +513,14 @@ static inline int iop13xx_cpu_id(void)
#define IOP13XX_PBI_LR1 IOP13XX_PBI_OFFSET(0x14)

#define IOP13XX_PROCESSOR_FREQ IOP13XX_REG_ADDR32(0x2180)

/* Watchdog timer definitions */
#define IOP_WDTCR_EN_ARM 0x1e1e1e1e
#define IOP_WDTCR_EN 0xe1e1e1e1
#define IOP_WDTCR_DIS_ARM 0x1f1f1f1f
#define IOP_WDTCR_DIS 0xf1f1f1f1
#define IOP_RCSR_WDT (1 << 5) /* reset caused by watchdog timer */
#define IOP13XX_WDTSR_WRITE_EN (1 << 31) /* used to speed up reset requests */
#define IOP13XX_WDTCR_IB_RESET (1 << 0)

#endif /* _IOP13XX_HW_H_ */
Loading

0 comments on commit bfb7b1b

Please sign in to comment.