--- a/drivers/watchdog/bcm47xx_wdt.c +++ b/drivers/watchdog/bcm47xx_wdt.c @@ -31,6 +31,7 @@ #define WDT_DEFAULT_TIME 30 /* seconds */ #define WDT_MAX_TIME 255 /* seconds */ +#define WDT_SHIFT 15 /* 32.768 KHz on cores with slow WDT clock */ static int wdt_time = WDT_DEFAULT_TIME; static int nowayout = WATCHDOG_NOWAYOUT; @@ -50,11 +51,11 @@ static unsigned long bcm47xx_wdt_busy; static char expect_release; static struct timer_list wdt_timer; static atomic_t ticks; +static int needs_sw_scale; -static inline void bcm47xx_wdt_hw_start(void) +static inline void bcm47xx_wdt_hw_start(u32 ticks) { - /* this is 2,5s on 100Mhz clock and 2s on 133 Mhz */ - ssb_watchdog_timer_set(&ssb_bcm47xx, 0xfffffff); + ssb_watchdog_timer_set(&ssb_bcm47xx, ticks); } static inline int bcm47xx_wdt_hw_stop(void) @@ -65,33 +66,34 @@ static inline int bcm47xx_wdt_hw_stop(vo static void bcm47xx_timer_tick(unsigned long unused) { if (!atomic_dec_and_test(&ticks)) { - bcm47xx_wdt_hw_start(); + /* This is 2,5s on 100Mhz clock and 2s on 133 Mhz */ + bcm47xx_wdt_hw_start(0xfffffff); mod_timer(&wdt_timer, jiffies + HZ); } else { - printk(KERN_CRIT DRV_NAME "Watchdog will fire soon!!!\n"); + printk(KERN_CRIT DRV_NAME ": Watchdog will fire soon!!!\n"); } } -static inline void bcm47xx_wdt_pet(void) +static void bcm47xx_wdt_pet(void) { - atomic_set(&ticks, wdt_time); + if(needs_sw_scale) + atomic_set(&ticks, wdt_time); + else + bcm47xx_wdt_hw_start(wdt_time << WDT_SHIFT); } static void bcm47xx_wdt_start(void) { bcm47xx_wdt_pet(); - bcm47xx_timer_tick(0); -} - -static void bcm47xx_wdt_pause(void) -{ - del_timer_sync(&wdt_timer); - bcm47xx_wdt_hw_stop(); + if(needs_sw_scale) + bcm47xx_timer_tick(0); } static void bcm47xx_wdt_stop(void) { - bcm47xx_wdt_pause(); + if(needs_sw_scale) + del_timer_sync(&wdt_timer); + bcm47xx_wdt_hw_stop(); } static int bcm47xx_wdt_settimeout(int new_time) @@ -243,7 +245,15 @@ static int __init bcm47xx_wdt_init(void) if (bcm47xx_wdt_hw_stop() < 0) return -ENODEV; - setup_timer(&wdt_timer, bcm47xx_timer_tick, 0L); + /* FIXME Other cores */ + if(ssb_bcm47xx.chip_id == 0x5354) { + /* Slow WDT clock, no pre-scaling */ + needs_sw_scale = 0; + } else { + /* Fast WDT clock, needs software pre-scaling */ + needs_sw_scale = 1; + setup_timer(&wdt_timer, bcm47xx_timer_tick, 0L); + } if (bcm47xx_wdt_settimeout(wdt_time)) { bcm47xx_wdt_settimeout(WDT_DEFAULT_TIME);