OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [drivers/] [char/] [mcfwatchdog.c] - Rev 1765

Compare with Previous | Blame | View Log

/***************************************************************************/
 
/*
 *	linux/drivers/char/mcfwatchdog.c
 *
 *	Copyright (C) 1999-2000, Greg Ungerer (gerg@moreton.com.au)
 */
 
/***************************************************************************/
 
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/param.h>
#include <asm/irq.h>
#include <asm/traps.h>
#include <asm/machdep.h>
#include <asm/coldfire.h>
#include <asm/mcftimer.h>
#include <asm/mcfsim.h>
#include <asm/irq.h>
#include <asm/delay.h>
 
/***************************************************************************/
 
/*
 *	Define the watchdog vector.
 */
#define	IRQ_WATCHDOG	250
 
/***************************************************************************/
 
void	watchdog_alive(unsigned long arg);
void	watchdog_init(void);
void	watchdog_timeout(int irq, void *dummy, struct pt_regs *fp);
 
extern void	dump(struct pt_regs *fp);
 
 
/*
 *	Data for registering the watchdog alive routine with ticker.
 */
struct timer_list	watchdog_timerlist = {
	NULL, NULL, 0, 0, watchdog_alive
};
 
 
#if CONFIG_OLDMASK
/*
 *	The old mask 5307 has a broken watchdog timer. It will interrupt
 *	you regardless of writing to its "alive" register. It can still
 *	be useful but you have to play some tricks with it. This code
 *	supports a clock ticker timeout. If the right number of clock
 *	ticks are not counted then it is assumed that the watchdog saved
 *	us from a bad bus cycle.
 *
 *	Hardwire the reference counts for different boards. Ugly, but
 *	there is really no other way to hold it all together...
 */
#ifdef CONFIG_eLIA
#define	SWTREF_COUNT	37
#else
#define	SWTREF_COUNT	30
#endif
 
int	swt_doit = 0;			/* Start delay before tripping */
int	swt_lastjiffies = 0;		/* Tick count at last watchdog */
int	swt_reference = SWTREF_COUNT;	/* Refereence tick count */
#endif
 
/***************************************************************************/
 
/*
 *	Software Watchdog Timer enable. Seems to be the same across all
 *	ColdFire CPu members.
 */
void watchdog_enable(void)
{
	volatile unsigned char	*mbar;
 
	mbar = (volatile unsigned char *) MCF_MBAR;
	*(mbar + MCFSIM_SWSR) = 0x55;
	*(mbar + MCFSIM_SWSR) = 0xaa;
	*(mbar + MCFSIM_SYPCR) = 0xbe;
}
 
/***************************************************************************/
 
void watchdog_disable(void)
{
	volatile unsigned char	*mbar;
 
	mbar = (volatile unsigned char *) MCF_MBAR;
	*(mbar + MCFSIM_SWSR) = 0x55;
	*(mbar + MCFSIM_SWSR) = 0xaa;
	*(mbar + MCFSIM_SYPCR) = 0x00 /*0x3e*/;
}
 
/***************************************************************************/
 
#define	TIMEDELAY	45
 
/*
 *	Process a watchdog timeout interrupt. For a normal clean watchdog
 *	we just do a process dump. For old broken 5307 we need to verify
 *	if this was a real watchdog event or not...
 */
void watchdog_timeout(int irq, void *dummy, struct pt_regs *fp)
{
#ifdef CONFIG_OLDMASK
	/*
	 *	Debuging code for software watchdog. If we get in here
	 *	and timer interrupt counts don't match we know that a
	 *	bad external bus cycle must have locked the CPU.
	 */
	if ((swt_doit++ > TIMEDELAY) &&
	    ((swt_lastjiffies + swt_reference) > jiffies)) {
		static int	inside = 0;
 
		if (inside) {
			cli();
			watchdog_disable();
			mcf_setimr(mcf_getimr() | MCFSIM_IMR_SWD);
			printk("%s(%d): Double WATCHDOG PANIC!!\n",
				__FILE__, __LINE__);
			for (;;)
				;
		}
 
		inside++;
		swt_doit = TIMEDELAY - 8;	/* 8 seconds grace */
		printk("WATCHDOG: expired last=%d(%d) jiffies=%d!\n",
			swt_lastjiffies, swt_reference, jiffies);
		dump(fp);
		force_sig(SIGSEGV, current);
		inside = 0;
	}
	swt_lastjiffies = jiffies;
#else
	printk("WATCHDOG: expired!\n");
	dump(fp);
#endif /* CONFIG_OLDMASK */
}
 
/***************************************************************************/
 
void watchdog_init(void)
{
	volatile unsigned char	*mbar;
 
	printk("WATCHDOG: initializing at vector=%d\n", IRQ_WATCHDOG);
	request_irq(IRQ_WATCHDOG, watchdog_timeout, SA_INTERRUPT,
		"Watchdog Timer", NULL);
 
	watchdog_timerlist.expires = jiffies + 1;
	add_timer(&watchdog_timerlist);
 
	mbar = (volatile unsigned char *) MCF_MBAR;
	*(mbar + MCFSIM_SWDICR) = MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3;
	*(mbar + MCFSIM_SWIVR) = IRQ_WATCHDOG;
	mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_SWD);
	watchdog_enable();
}
 
/***************************************************************************/
 
void watchdog_alive(unsigned long arg)
{
	volatile unsigned char	*mbar;
 
	mbar = (volatile unsigned char *) MCF_MBAR;
	*(mbar + MCFSIM_SWSR) = 0x55;
	*(mbar + MCFSIM_SWSR) = 0xaa;
 
	/* Re-arm the watchdog alive poll */
	watchdog_timerlist.expires = jiffies + 1;
	add_timer(&watchdog_timerlist);
}
 
/***************************************************************************/
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.