/* Module and version information */ #define DRV_NAME "iTCO_wdt" #define DRV_VERSION "1.11"
/* Includes */ #include <linux/acpi.h> /* For ACPI support */ #include <linux/bits.h> /* For BIT() */ #include <linux/module.h> /* For module specific items */ #include <linux/moduleparam.h> /* For new moduleparam's */ #include <linux/types.h> /* For standard types (like size_t) */ #include <linux/errno.h> /* For the -ENODEV/... values */ #include <linux/kernel.h> /* For printk/panic/... */ #include <linux/watchdog.h> /* For the watchdog specific items */ #include <linux/init.h> /* For __init/__exit/... */ #include <linux/fs.h> /* For file operations */ #include <linux/platform_device.h> /* For platform_driver framework */ #include <linux/pci.h> /* For pci functions */ #include <linux/ioport.h> /* For io-port access */ #include <linux/uaccess.h> /* For copy_to_user/put_user/... */ #include <linux/io.h> /* For inb/outb/... */ #include <linux/platform_data/itco_wdt.h> #include <linux/mfd/intel_pmc_bxt.h>
#include"iTCO_vendor.h"
/* Address definitions for the TCO */ /* TCO base address */ #define TCOBASE(p) ((p)->tco_res->start) /* SMI Control and Enable Register */ #define SMI_EN(p) ((p)->smi_res->start)
/* TCO version/generation */ unsignedint iTCO_version; struct resource *tco_res; struct resource *smi_res; /* *NO_REBOOTflagisMemory-MappedGCSregisterbit5(TCOversion2), *ormemory-mappedPMCregisterbit4(TCOversion3).
*/ unsignedlong __iomem *gcs_pmc; /* the PCI-device */ struct pci_dev *pci_dev; /* whether or not the watchdog has been suspended */ bool suspended; /* no reboot API private data */ void *no_reboot_priv; /* no reboot update function pointer */ int (*update_no_reboot_bit)(void *p, bool set);
};
/* disable chipset's NO_REBOOT bit */ if (p->update_no_reboot_bit(p->no_reboot_priv, false)) {
dev_err(wd_dev->parent, "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 (p->iTCO_version >= 2)
outw(0x01, TCO_RLD(p)); elseif (p->iTCO_version == 1)
outb(0x01, TCO_RLD(p));
/* Bit 11: TCO Timer Halt -> 0 = The TCO timer is enabled to count */
val = inw(TCO1_CNT(p));
val &= 0xf7ff;
outw(val, TCO1_CNT(p));
val = inw(TCO1_CNT(p));
/* Reload the timer by writing to the TCO Timer Counter register */ if (p->iTCO_version >= 2) {
outw(0x01, TCO_RLD(p));
} elseif (p->iTCO_version == 1) { /* Reset the timeout status bit so that the timer
* needs to count down twice again before rebooting */
outw(0x0008, TCO1_STS(p)); /* write 1 to clear bit */
/* For TCO v1 the timer counts down twice before rebooting */ if (p->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 ((p->iTCO_version >= 2 && tmrval > 0x3ff) ||
(p->iTCO_version == 1 && tmrval > 0x03f)) return -EINVAL;
/* Write new heartbeat to watchdog */ if (p->iTCO_version >= 2) {
val16 = inw(TCOv2_TMR(p));
val16 &= 0xfc00;
val16 |= tmrval;
outw(val16, TCOv2_TMR(p));
val16 = inw(TCOv2_TMR(p));
/* Returns true if the watchdog was running */ staticbool iTCO_wdt_set_running(struct iTCO_wdt_private *p)
{
u16 val;
/* Bit 11: TCO Timer Halt -> 0 = The TCO timer is enabled */
val = inw(TCO1_CNT(p)); if (!(val & BIT(11))) {
set_bit(WDOG_HW_RUNNING, &p->wddev.status); returntrue;
} returnfalse;
}
/* Clear out the (probably old) status */ switch (p->iTCO_version) { case6: case5: case4:
outw(0x0008, TCO1_STS(p)); /* Clear the Time Out Status bit */
outw(0x0002, TCO2_STS(p)); /* Clear SECOND_TO_STS bit */ break; case3:
outl(0x20008, TCO1_STS(p)); break; case2: case1: default:
outw(0x0008, TCO1_STS(p)); /* Clear the Time Out Status bit */
outw(0x0002, TCO2_STS(p)); /* Clear SECOND_TO_STS bit */
outw(0x0004, TCO2_STS(p)); /* Clear BOOT_STS bit */ break;
}
if (!iTCO_wdt_set_running(p)) { /* *IfthewatchdogwasnotrunningsetNO_REBOOTnowto *preventlaterreboots.
*/
p->update_no_reboot_bit(p->no_reboot_priv, true);
}
/* Check that the heartbeat value is within it's range;
if not reset to the default */ if (iTCO_wdt_set_timeout(&p->wddev, heartbeat)) {
ret = iTCO_wdt_set_timeout(&p->wddev, WATCHDOG_TIMEOUT); if (ret != 0) {
dev_err(dev, "Failed to set watchdog timeout (%d)\n", WATCHDOG_TIMEOUT); return ret;
}
dev_info(dev, "timeout value out of range, using %d\n",
WATCHDOG_TIMEOUT);
heartbeat = WATCHDOG_TIMEOUT;
}
watchdog_stop_on_reboot(&p->wddev);
watchdog_stop_on_unregister(&p->wddev);
ret = devm_watchdog_register_device(dev, &p->wddev); if (ret != 0) return ret;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.