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; }
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; }
/* * 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 */ }
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; }