ld LITMUS^RT 2008 version (for reference).
aboutsummaryrefslogblamecommitdiffstats
path: root/drivers/char/watchdog/iTCO_wdt.c
blob: 7eac922df8678cecbcde093a53f7da2d3c886257 (plain) (tree)




































                                                                             



                                                                      








                                                            

                                     


                                     






                                                                                      








                                                                           



















                                            


                                          






















                                       
                             

                      


























                                                                                                            
                                                                                                            

                                                                                                            




























                                                                                                                

                                                                                                  









                                                                                                                                                         














                                                                                                     



























































                                                                           

                                                                    























                                                                                                     

                                                        



















                                                                           

                                                                        

























                                                                           

                                              
















































                                                        

                               





































































                                                                                   


























































                                                                  

                                      






                                                              
                                       



         

















                                               



                            
                                                                                                            















                                                                       
                                  















                                                                                            
                                                                                














































                                                                                                                   



                                                                                     
                                  






                                                                              




                                               
                                           
                                      


                   
                                  






                                            


                                               
                                           
                                      

 
                                                      









                                                           
                                                               













                                                           
                                                       



                                      


















































                                                                                          







                                                            
                            

                                     
/*
 *	intel TCO Watchdog Driver (Used in i82801 and i6300ESB chipsets)
 *
 *	(c) Copyright 2006 Wim Van Sebroeck <wim@iguana.be>.
 *
 *	This program is free software; you can redistribute it and/or
 *	modify it under the terms of the GNU General Public License
 *	as published by the Free Software Foundation; either version
 *	2 of the License, or (at your option) any later version.
 *
 *	Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor
 *	provide warranty for any of this software. This material is
 *	provided "AS-IS" and at no charge.
 *
 *	The TCO watchdog is implemented in the following I/O controller hubs:
 *	(See the intel documentation on http://developer.intel.com.)
 *	82801AA  (ICH)       : document number 290655-003, 290677-014,
 *	82801AB  (ICHO)      : document number 290655-003, 290677-014,
 *	82801BA  (ICH2)      : document number 290687-002, 298242-027,
 *	82801BAM (ICH2-M)    : document number 290687-002, 298242-027,
 *	82801CA  (ICH3-S)    : document number 290733-003, 290739-013,
 *	82801CAM (ICH3-M)    : document number 290716-001, 290718-007,
 *	82801DB  (ICH4)      : document number 290744-001, 290745-020,
 *	82801DBM (ICH4-M)    : document number 252337-001, 252663-005,
 *	82801E   (C-ICH)     : document number 273599-001, 273645-002,
 *	82801EB  (ICH5)      : document number 252516-001, 252517-003,
 *	82801ER  (ICH5R)     : document number 252516-001, 252517-003,
 *	82801FB  (ICH6)      : document number 301473-002, 301474-007,
 *	82801FR  (ICH6R)     : document number 301473-002, 301474-007,
 *	82801FBM (ICH6-M)    : document number 301473-002, 301474-007,
 *	82801FW  (ICH6W)     : document number 301473-001, 301474-007,
 *	82801FRW (ICH6RW)    : document number 301473-001, 301474-007,
 *	82801GB  (ICH7)      : document number 307013-002, 307014-009,
 *	82801GR  (ICH7R)     : document number 307013-002, 307014-009,
 *	82801GDH (ICH7DH)    : document number 307013-002, 307014-009,
 *	82801GBM (ICH7-M)    : document number 307013-002, 307014-009,
 *	82801GHM (ICH7-M DH) : document number 307013-002, 307014-009,
 *	82801HB  (ICH8)      : document number 313056-002, 313057-004,
 *	82801HR  (ICH8R)     : document number 313056-002, 313057-004,
 *	82801HH  (ICH8DH)    : document number 313056-002, 313057-004,
 *	82801HO  (ICH8DO)    : document number 313056-002, 313057-004,
 *	6300ESB  (6300ESB)   : document number 300641-003
 */

/*
 *	Includes, defines, variables, module parameters, ...
 */

/* Module and version information */
#define DRV_NAME        "iTCO_wdt"
#define DRV_VERSION     "1.01"
#define DRV_RELDATE     "11-Nov-2006"
#define PFX		DRV_NAME ": "

/* Includes */
#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/miscdevice.h>		/* For MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR) */
#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/spinlock.h>		/* For spin_lock/spin_unlock/... */

#include <asm/uaccess.h>		/* For copy_to_user/put_user/... */
#include <asm/io.h>			/* For inb/outb/... */

/* TCO related info */
enum iTCO_chipsets {
	TCO_ICH = 0,	/* ICH */
	TCO_ICH0,	/* ICH0 */
	TCO_ICH2,	/* ICH2 */
	TCO_ICH2M,	/* ICH2-M */
	TCO_ICH3,	/* ICH3-S */
	TCO_ICH3M,	/* ICH3-M */
	TCO_ICH4,	/* ICH4 */
	TCO_ICH4M,	/* ICH4-M */
	TCO_CICH,	/* C-ICH */
	TCO_ICH5,	/* ICH5 & ICH5R */
	TCO_6300ESB,	/* 6300ESB */
	TCO_ICH6,	/* ICH6 & ICH6R */
	TCO_ICH6M,	/* ICH6-M */
	TCO_ICH6W,	/* ICH6W & ICH6RW */
	TCO_ICH7,	/* ICH7 & ICH7R */
	TCO_ICH7M,	/* ICH7-M */
	TCO_ICH7MDH,	/* ICH7-M DH */
	TCO_ICH8,	/* ICH8 & ICH8R */
	TCO_ICH8DH,	/* ICH8DH */
	TCO_ICH8DO,	/* ICH8DO */
};

static struct {
	char *name;
	unsigned int iTCO_version;
} iTCO_chipset_info[] __devinitdata = {
	{"ICH", 1},
	{"ICH0", 1},
	{"ICH2", 1},
	{"ICH2-M", 1},
	{"ICH3-S", 1},
	{"ICH3-M", 1},
	{"ICH4", 1},
	{"ICH4-M", 1},
	{"C-ICH", 1},
	{"ICH5 or ICH5R", 1},
	{"6300ESB", 1},
	{"ICH6 or ICH6R", 2},
	{"ICH6-M", 2},
	{"ICH6W or ICH6RW", 2},
	{"ICH7 or ICH7R", 2},
	{"ICH7-M", 2},
	{"ICH7-M DH", 2},
	{"ICH8 or ICH8R", 2},
	{"ICH8DH", 2},
	{"ICH8DO", 2},
	{NULL,0}
};

/*
 * This data only exists for exporting the supported PCI ids
 * via MODULE_DEVICE_TABLE.  We do not actually register a
 * pci_driver, because the I/O Controller Hub has also other
 * functions that probably will be registered by other drivers.
 */
static struct pci_device_id iTCO_wdt_pci_tbl[] = {
	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH     },
	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH0    },
	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH2    },
	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH2M   },
	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH3    },
	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH3M   },
	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH4    },
	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH4M   },
	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_CICH    },
	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH5    },
	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_6300ESB },
	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH6    },
	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH6M   },
	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_2,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH6W   },
	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7    },
	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7M   },
	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7MDH },
	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_0,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8    },
	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_2,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8DH  },
	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_3,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8DO  },
	{ 0, },			/* End of list */
};
MODULE_DEVICE_TABLE (pci, iTCO_wdt_pci_tbl);

/* Address definitions for the TCO */
#define	TCOBASE		iTCO_wdt_private.ACPIBASE + 0x60	/* TCO base address                */
#define	SMI_EN		iTCO_wdt_private.ACPIBASE + 0x30	/* SMI Control and Enable Register */

#define TCO_RLD		TCOBASE + 0x00	/* TCO Timer Reload and Current 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	*/

/* internal variables */
static unsigned long is_active;
static char expect_release;
static struct {				/* this is private data for the iTCO_wdt device */
	unsigned int iTCO_version;	/* TCO version/generation */
	unsigned long ACPIBASE;		/* The cards ACPIBASE address (TCOBASE = ACPIBASE+0x60) */
	unsigned long __iomem *gcs;	/* NO_REBOOT flag is Memory-Mapped GCS register bit 5 (TCO version 2) */
	spinlock_t io_lock;		/* the lock for io operations */
	struct pci_dev *pdev;		/* the PCI-device */
} iTCO_wdt_private;

static struct platform_device *iTCO_wdt_platform_device;	/* the watchdog platform device */

/* module parameters */
#define WATCHDOG_HEARTBEAT 30	/* 30 sec default heartbeat */
static int heartbeat = WATCHDOG_HEARTBEAT;  /* in seconds */
module_param(heartbeat, int, 0);
MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2<heartbeat<39 (TCO v1) or 613 (TCO v2), default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");

static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");

/* iTCO Vendor Specific Support hooks */
#ifdef CONFIG_ITCO_VENDOR_SUPPORT
extern void iTCO_vendor_pre_start(unsigned long, unsigned int);
extern void iTCO_vendor_pre_stop(unsigned long);
extern void iTCO_vendor_pre_keepalive(unsigned long, unsigned int);
extern void iTCO_vendor_pre_set_heartbeat(unsigned int);
extern int iTCO_vendor_check_noreboot_on(void);
#else
#define iTCO_vendor_pre_start(acpibase, heartbeat)	{}
#define iTCO_vendor_pre_stop(acpibase)			{}
#define iTCO_vendor_pre_keepalive(acpibase,heartbeat)	{}
#define iTCO_vendor_pre_set_heartbeat(heartbeat)	{}
#define iTCO_vendor_check_noreboot_on()			1	/* 1=check noreboot; 0=don't check */
#endif

/*
 * Some TCO specific functions
 */

static inline unsigned int seconds_to_ticks(int seconds)
{
	/* the internal timer is stored as ticks which decrement
	 * every 0.6 seconds */
	return (seconds * 10) / 6;
}

static void iTCO_wdt_set_NO_REBOOT_bit(void)
{
	u32 val32;

	/* Set the NO_REBOOT bit: this disables reboots */
	if (iTCO_wdt_private.iTCO_version == 2) {
		val32 = readl(iTCO_wdt_private.gcs);
		val32 |= 0x00000020;
		writel(val32, iTCO_wdt_private.gcs);