Esempio n. 1
0
static int __init ppc405wd_init(void)
{
	misc_register(&ppc405wd_miscdev);
	printk(KERN_NOTICE "PPC 405 watchdog driver v%s\n", VERSION);
	if (wdt_period == 0)
		wdt_period = WDT_DEFAULT_PERIOD;
	heartbeat_count(0) = wdt_period * HZ;
	heartbeat_reset(0) = 1;
	return 0;
}	
Esempio n. 2
0
void 
ppc4xx_wdt_heartbeat(void)
{
	if (wdt_default ){
		/* default used until wdt inits */
		heartbeat_count(0) = wdt_period * HZ;
		wdt_default = 0;
	}	
	if (wdt_enable)
		machine_restart("Watchdog Timer Timed out, system reset!");
	
	heartbeat_reset(0) = 1;
}
Esempio n. 3
0
/*
 * timer_interrupt - gets called when the decrementer overflows,
 * with interrupts disabled.
 * We set it up to overflow again in 1/HZ seconds.
 */
int timer_interrupt(struct pt_regs * regs)
{
	int next_dec;
	unsigned long cpu = smp_processor_id();
	unsigned jiffy_stamp = last_jiffy_stamp(cpu);
	extern void do_IRQ(struct pt_regs *);

	if (atomic_read(&ppc_n_lost_interrupts) != 0)
		do_IRQ(regs);

	hardirq_enter(cpu);

	while ((next_dec = tb_ticks_per_jiffy - tb_delta(&jiffy_stamp)) < 0) {
		jiffy_stamp += tb_ticks_per_jiffy;
		if (!user_mode(regs))
			ppc_do_profile(instruction_pointer(regs));
		if (unlikely(!heartbeat_count(cpu)--)
				&& heartbeat_reset(cpu)) {
			ppc_md.heartbeat();
			heartbeat_count(cpu) = heartbeat_reset(cpu);
		}
	  	if (cpu)
			continue;

		/* We are in an interrupt, no need to save/restore flags */
		write_lock(&xtime_lock);
		tb_last_stamp = jiffy_stamp;
		do_timer(regs);

		/*
		 * update the rtc when needed, this should be performed on the
		 * right fraction of a second. Half or full second ?
		 * Full second works on mk48t59 clocks, others need testing.
		 * Note that this update is basically only used through
		 * the adjtimex system calls. Setting the HW clock in
		 * any other way is a /dev/rtc and userland business.
		 * This is still wrong by -0.5/+1.5 jiffies because of the
		 * timer interrupt resolution and possible delay, but here we
		 * hit a quantization limit which can only be solved by higher
		 * resolution timers and decoupling time management from timer
		 * interrupts. This is also wrong on the clocks
		 * which require being written at the half second boundary.
		 * We should have an rtc call that only sets the minutes and
		 * seconds like on Intel to avoid problems with non UTC clocks.
		 */
		if ( ppc_md.set_rtc_time && (time_status & STA_UNSYNC) == 0 &&
		     xtime.tv_sec - last_rtc_update >= 659 &&
		     abs(xtime.tv_usec - (1000000-1000000/HZ)) < 500000/HZ &&
		     jiffies - wall_jiffies == 1) {
		  	if (ppc_md.set_rtc_time(xtime.tv_sec+1 + time_offset) == 0)
				last_rtc_update = xtime.tv_sec+1;
			else
				/* Try again one minute later */
				last_rtc_update += 60;
		}
		write_unlock(&xtime_lock);
	}
	if (!disarm_decr[cpu])
		set_dec(next_dec);
	last_jiffy_stamp(cpu) = jiffy_stamp;

#ifdef CONFIG_SMP
	smp_local_timer_interrupt(regs);
#endif /* CONFIG_SMP */

	hardirq_exit(cpu);

	if (softirq_pending(cpu))
		do_softirq();

	return 1; /* lets ret_from_int know we can do checks */
}
Esempio n. 4
0
static int ppc405wd_ioctl(struct inode *inode, struct file *file,
	unsigned int cmd, unsigned long arg)
{
	unsigned long period;
	int status;
	int state;
	static struct watchdog_info ident = {
		WDIOF_KEEPALIVEPING,
		0,
		"PPC 405 watchdog"
	};
                                        
	switch (cmd) {
		case WDIOC_GETSTATUS:
			status = ppc405wd_opened;

			if (copy_to_user((int *)arg, &status, sizeof(int)))
				return -EFAULT;
			break;
		case WDIOC_GETSUPPORT:
			if (copy_to_user((struct watchdog_info *)arg, &ident, 
			    sizeof(ident))) {
				return -EFAULT;
			}
			break;
		case WDIOC_KEEPALIVE:
		        ppc405wd_update_timer();
			break;
		case WDIOC_SETOPTIONS:
			if(copy_from_user(&state, (int*) arg, sizeof(int)))
				return -EFAULT;
			if (state & WDIOS_DISABLECARD) {
				wdt_enable = 0;
				printk(KERN_NOTICE "Soft watchdog timer is disabled\n");
				break;
			}
                        if (state & WDIOS_ENABLECARD) {
				wdt_enable = 1;
				heartbeat_count(0) = wdt_period * HZ;
				heartbeat_reset(0) = 1;
				printk(KERN_NOTICE "Soft watchdog timer is enabled\n");
				break;
			}
		case WDIOC_GETPERIOD:
			/* return watchdog period (units = microseconds) */
			period = (wdt_period / HZ) * MICROSECBASE;
			if (copy_to_user((unsigned long *)arg, &period, 
			    sizeof(period))) {
				return -EFAULT;
			}
			break;
		case WDIOC_SETPERIOD:
			/*
			** set watchdog period (units = microseconds)
			** value of zero means maximum
			**
			** Don't set a watchdog period to a value less than
			** the requested value (period will be rounded up to
			** next available interval the watchdog supports).
			**
			** The software watchdog will expire at some point in
			** the range of (rounded up period) ..
			** (rounded up period + 1 jiffie).  If interrupts are
			** disabled so that the software watchdog is unable to
			** reset the system, then the hardware watchdog will
			** eventually reset the system.
			*/
			if (copy_from_user(&period, (unsigned long *)arg,
			    sizeof(period))) {
				return -EFAULT;
			}

			/* 
			** This code assumes HZ is 100.  Need to remove that
			** assumption.
			*/

			/*
			** The minimum period of ppc405wd_timer is a jiffie,
			** which is 10 msec when HZ is 100.  The units of
			** wdt_period is jiffies.
			**
			** The new timer period will be used at the next
			** heartbeat.
			*/
			if (period == 0)
				period = MAXONEHOUR * MICROSECBASE;        

			heartbeat_count(0) = (period / TENMSBASE) +
				(period % TENMSBASE ? 1 : 0);
			ppc405wd_update_timer();

			break;
		default:
			return -ENOIOCTLCMD;

	}
	return 0;
}