/* Address definitions for the TCO */ /* TCO base address */ #define TCOBASE (iTCO_wdt_private.tco_res->start) /* SMI Control and Enable Register */ #define SMI_EN (iTCO_wdt_private.smi_res->start)
#define TCO_RLD (TCOBASE + 0x00) /* TCO Timer Reload and Curr. Value */ #define TCOv1_TMR (TCOBASE + 0x01) /* TCOv1 Timer Initial Value */ #define TCO_DAT_IN (TCOBASE + 0x02) /* TCO Data In Register */ #define TCO_DAT_OUT (TCOBASE + 0x03) /* TCO Data Out Register */ #define TCO1_STS (TCOBASE + 0x04) /* TCO1 Status Register */ #define TCO2_STS (TCOBASE + 0x06) /* TCO2 Status Register */ #define TCO1_CNT (TCOBASE + 0x08) /* TCO1 Control Register */ #define TCO2_CNT (TCOBASE + 0x0a) /* TCO2 Control Register */ #define TCOv2_TMR (TCOBASE + 0x12) /* TCOv2 Timer Initial Value */
默认超时时间为30秒。nowayout由内核配置CONFIG_WATCHDOG_NOWAYOUT来确定。内核配置的解释为:Disable watchdog shutdown on close。如果为true,表示关闭watchdog设备也不会停止看门狗。亦即一旦使能看门狗,是无关法关闭的,是没有退路的,所以叫“no way out”。 5、向系统注册看门狗设备。并打印超时时间。
1 2 3 4 5 6 7 8
ret = watchdog_register_device(&iTCO_wdt_watchdog_dev); if (ret != 0) { pr_err("cannot register watchdog device (err=%d)\n", ret); goto unreg_tco; }
/* disable chipset's NO_REBOOT bit */ if (iTCO_wdt_unset_NO_REBOOT_bit()) { spin_unlock(&iTCO_wdt_private.io_lock); pr_err("failed to reset NO_REBOOT flag, reboot disabled by hardware/BIOS\n"); return -EIO; }
/* Force the timer to its reload value by writing to the TCO_RLD register */ if (iTCO_wdt_private.iTCO_version >= 2) outw(0x01, TCO_RLD); else if (iTCO_wdt_private.iTCO_version == 1) outb(0x01, TCO_RLD);
// 0表示TCO计时,1表示禁止 /* Bit 11: TCO Timer Halt -> 0 = The TCO timer is enabled to count */ val = inw(TCO1_CNT); val &= 0xf7ff; outw(val, TCO1_CNT); val = inw(TCO1_CNT); spin_unlock(&iTCO_wdt_private.io_lock);
// 写1到TCO_RLD寄存器,重新计时 /* Reload the timer by writing to the TCO Timer Counter register */ if (iTCO_wdt_private.iTCO_version >= 2) { outw(0x01, TCO_RLD); } else if (iTCO_wdt_private.iTCO_version == 1) { /* Reset the timeout status bit so that the timer * needs to count down twice again before rebooting */ outw(0x0008, TCO1_STS); /* write 1 to clear bit */
static int iTCO_wdt_set_timeout(struct watchdog_device *wd_dev, unsigned int t) { unsigned int val16; unsigned char val8; unsigned int tmrval;
tmrval = seconds_to_ticks(t); // 时间(单位为秒)转换为tick
/* For TCO v1 the timer counts down twice before rebooting */ if (iTCO_wdt_private.iTCO_version == 1) tmrval /= 2;
/* from the specs: */ /* "Values of 0h-3h are ignored and should not be attempted" */ if (tmrval < 0x04) return -EINVAL; if (((iTCO_wdt_private.iTCO_version >= 2) && (tmrval > 0x3ff)) || ((iTCO_wdt_private.iTCO_version == 1) && (tmrval > 0x03f))) return -EINVAL;
iTCO_vendor_pre_set_heartbeat(tmrval);
// 将新的超时时间写入TMR寄存器 /* Write new heartbeat to watchdog */ if (iTCO_wdt_private.iTCO_version >= 2) { spin_lock(&iTCO_wdt_private.io_lock); val16 = inw(TCOv2_TMR); val16 &= 0xfc00; val16 |= tmrval; outw(val16, TCOv2_TMR); val16 = inw(TCOv2_TMR); spin_unlock(&iTCO_wdt_private.io_lock);
/* Set the NO_REBOOT bit: this disables reboots */ if (iTCO_wdt_private.iTCO_version == 3) { val32 = readl(iTCO_wdt_private.gcs_pmc); val32 |= 0x00000010; // bit4为NO_REBOOT标志 writel(val32, iTCO_wdt_private.gcs_pmc); } //... }
关于NO_REBOOT的解释如下:
No Reboot (NO_REBOOT) (no_reboot): This bit is set when the No Reboot strap is sampled high on COREPWROK. This bit may be set or cleared by software if the strap is sampled low but may not override the strap wh en it indicates No Reboot. When set, the TCO timer will count down and generate th e SMI# on the first timeout, but will not reboot on the second timeout.