watchdog: Convert iTCO_wdt driver to mfd model
This patch converts the iTCO_wdt driver to use the multi-function device driver model. It uses resources discovered by the lpc_ich driver, so that it no longer does its own PCI scanning. Signed-off-by: Aaron Sierra <asierra@xes-inc.com> Signed-off-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
This commit is contained in:
parent
16c5c023aa
commit
887c8ec721
7 changed files with 313 additions and 447 deletions
|
@ -785,7 +785,8 @@ config LPC_ICH
|
|||
help
|
||||
The LPC bridge function of the Intel ICH provides support for
|
||||
many functional units. This driver provides needed support for
|
||||
other drivers to control these functions, currently GPIO.
|
||||
other drivers to control these functions, currently GPIO and
|
||||
watchdog.
|
||||
|
||||
config MFD_RDC321X
|
||||
tristate "Support for RDC-R321x southbridge"
|
||||
|
|
|
@ -65,14 +65,42 @@
|
|||
#define ACPIBASE 0x40
|
||||
#define ACPIBASE_GPE_OFF 0x28
|
||||
#define ACPIBASE_GPE_END 0x2f
|
||||
#define ACPIBASE_SMI_OFF 0x30
|
||||
#define ACPIBASE_SMI_END 0x33
|
||||
#define ACPIBASE_TCO_OFF 0x60
|
||||
#define ACPIBASE_TCO_END 0x7f
|
||||
#define ACPICTRL 0x44
|
||||
|
||||
#define ACPIBASE_GCS_OFF 0x3410
|
||||
#define ACPIBASE_GCS_END 0x3414
|
||||
|
||||
#define GPIOBASE 0x48
|
||||
#define GPIOCTRL 0x4C
|
||||
|
||||
#define RCBABASE 0xf0
|
||||
|
||||
#define wdt_io_res(i) wdt_res(0, i)
|
||||
#define wdt_mem_res(i) wdt_res(ICH_RES_MEM_OFF, i)
|
||||
#define wdt_res(b, i) (&wdt_ich_res[(b) + (i)])
|
||||
|
||||
static int lpc_ich_acpi_save = -1;
|
||||
static int lpc_ich_gpio_save = -1;
|
||||
|
||||
static struct resource wdt_ich_res[] = {
|
||||
/* ACPI - TCO */
|
||||
{
|
||||
.flags = IORESOURCE_IO,
|
||||
},
|
||||
/* ACPI - SMI */
|
||||
{
|
||||
.flags = IORESOURCE_IO,
|
||||
},
|
||||
/* GCS */
|
||||
{
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource gpio_ich_res[] = {
|
||||
/* GPIO */
|
||||
{
|
||||
|
@ -85,10 +113,17 @@ static struct resource gpio_ich_res[] = {
|
|||
};
|
||||
|
||||
enum lpc_cells {
|
||||
LPC_GPIO = 0,
|
||||
LPC_WDT = 0,
|
||||
LPC_GPIO,
|
||||
};
|
||||
|
||||
static struct mfd_cell lpc_ich_cells[] = {
|
||||
[LPC_WDT] = {
|
||||
.name = "iTCO_wdt",
|
||||
.num_resources = ARRAY_SIZE(wdt_ich_res),
|
||||
.resources = wdt_ich_res,
|
||||
.ignore_resource_conflicts = true,
|
||||
},
|
||||
[LPC_GPIO] = {
|
||||
.name = "gpio_ich",
|
||||
.num_resources = ARRAY_SIZE(gpio_ich_res),
|
||||
|
@ -162,218 +197,276 @@ enum lpc_chipsets {
|
|||
struct lpc_ich_info lpc_chipset_info[] __devinitdata = {
|
||||
[LPC_ICH] = {
|
||||
.name = "ICH",
|
||||
.iTCO_version = 1,
|
||||
},
|
||||
[LPC_ICH0] = {
|
||||
.name = "ICH0",
|
||||
.iTCO_version = 1,
|
||||
},
|
||||
[LPC_ICH2] = {
|
||||
.name = "ICH2",
|
||||
.iTCO_version = 1,
|
||||
},
|
||||
[LPC_ICH2M] = {
|
||||
.name = "ICH2-M",
|
||||
.iTCO_version = 1,
|
||||
},
|
||||
[LPC_ICH3] = {
|
||||
.name = "ICH3-S",
|
||||
.iTCO_version = 1,
|
||||
},
|
||||
[LPC_ICH3M] = {
|
||||
.name = "ICH3-M",
|
||||
.iTCO_version = 1,
|
||||
},
|
||||
[LPC_ICH4] = {
|
||||
.name = "ICH4",
|
||||
.iTCO_version = 1,
|
||||
},
|
||||
[LPC_ICH4M] = {
|
||||
.name = "ICH4-M",
|
||||
.iTCO_version = 1,
|
||||
},
|
||||
[LPC_CICH] = {
|
||||
.name = "C-ICH",
|
||||
.iTCO_version = 1,
|
||||
},
|
||||
[LPC_ICH5] = {
|
||||
.name = "ICH5 or ICH5R",
|
||||
.iTCO_version = 1,
|
||||
},
|
||||
[LPC_6300ESB] = {
|
||||
.name = "6300ESB",
|
||||
.iTCO_version = 1,
|
||||
},
|
||||
[LPC_ICH6] = {
|
||||
.name = "ICH6 or ICH6R",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V6_GPIO,
|
||||
},
|
||||
[LPC_ICH6M] = {
|
||||
.name = "ICH6-M",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V6_GPIO,
|
||||
},
|
||||
[LPC_ICH6W] = {
|
||||
.name = "ICH6W or ICH6RW",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V6_GPIO,
|
||||
},
|
||||
[LPC_631XESB] = {
|
||||
.name = "631xESB/632xESB",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V6_GPIO,
|
||||
},
|
||||
[LPC_ICH7] = {
|
||||
.name = "ICH7 or ICH7R",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V7_GPIO,
|
||||
},
|
||||
[LPC_ICH7DH] = {
|
||||
.name = "ICH7DH",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V7_GPIO,
|
||||
},
|
||||
[LPC_ICH7M] = {
|
||||
.name = "ICH7-M or ICH7-U",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V7_GPIO,
|
||||
},
|
||||
[LPC_ICH7MDH] = {
|
||||
.name = "ICH7-M DH",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V7_GPIO,
|
||||
},
|
||||
[LPC_NM10] = {
|
||||
.name = "NM10",
|
||||
.iTCO_version = 2,
|
||||
},
|
||||
[LPC_ICH8] = {
|
||||
.name = "ICH8 or ICH8R",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V7_GPIO,
|
||||
},
|
||||
[LPC_ICH8DH] = {
|
||||
.name = "ICH8DH",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V7_GPIO,
|
||||
},
|
||||
[LPC_ICH8DO] = {
|
||||
.name = "ICH8DO",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V7_GPIO,
|
||||
},
|
||||
[LPC_ICH8M] = {
|
||||
.name = "ICH8M",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V7_GPIO,
|
||||
},
|
||||
[LPC_ICH8ME] = {
|
||||
.name = "ICH8M-E",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V7_GPIO,
|
||||
},
|
||||
[LPC_ICH9] = {
|
||||
.name = "ICH9",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V9_GPIO,
|
||||
},
|
||||
[LPC_ICH9R] = {
|
||||
.name = "ICH9R",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V9_GPIO,
|
||||
},
|
||||
[LPC_ICH9DH] = {
|
||||
.name = "ICH9DH",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V9_GPIO,
|
||||
},
|
||||
[LPC_ICH9DO] = {
|
||||
.name = "ICH9DO",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V9_GPIO,
|
||||
},
|
||||
[LPC_ICH9M] = {
|
||||
.name = "ICH9M",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V9_GPIO,
|
||||
},
|
||||
[LPC_ICH9ME] = {
|
||||
.name = "ICH9M-E",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V9_GPIO,
|
||||
},
|
||||
[LPC_ICH10] = {
|
||||
.name = "ICH10",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V10CONS_GPIO,
|
||||
},
|
||||
[LPC_ICH10R] = {
|
||||
.name = "ICH10R",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V10CONS_GPIO,
|
||||
},
|
||||
[LPC_ICH10D] = {
|
||||
.name = "ICH10D",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V10CORP_GPIO,
|
||||
},
|
||||
[LPC_ICH10DO] = {
|
||||
.name = "ICH10DO",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V10CORP_GPIO,
|
||||
},
|
||||
[LPC_PCH] = {
|
||||
.name = "PCH Desktop Full Featured",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V5_GPIO,
|
||||
},
|
||||
[LPC_PCHM] = {
|
||||
.name = "PCH Mobile Full Featured",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V5_GPIO,
|
||||
},
|
||||
[LPC_P55] = {
|
||||
.name = "P55",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V5_GPIO,
|
||||
},
|
||||
[LPC_PM55] = {
|
||||
.name = "PM55",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V5_GPIO,
|
||||
},
|
||||
[LPC_H55] = {
|
||||
.name = "H55",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V5_GPIO,
|
||||
},
|
||||
[LPC_QM57] = {
|
||||
.name = "QM57",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V5_GPIO,
|
||||
},
|
||||
[LPC_H57] = {
|
||||
.name = "H57",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V5_GPIO,
|
||||
},
|
||||
[LPC_HM55] = {
|
||||
.name = "HM55",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V5_GPIO,
|
||||
},
|
||||
[LPC_Q57] = {
|
||||
.name = "Q57",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V5_GPIO,
|
||||
},
|
||||
[LPC_HM57] = {
|
||||
.name = "HM57",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V5_GPIO,
|
||||
},
|
||||
[LPC_PCHMSFF] = {
|
||||
.name = "PCH Mobile SFF Full Featured",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V5_GPIO,
|
||||
},
|
||||
[LPC_QS57] = {
|
||||
.name = "QS57",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V5_GPIO,
|
||||
},
|
||||
[LPC_3400] = {
|
||||
.name = "3400",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V5_GPIO,
|
||||
},
|
||||
[LPC_3420] = {
|
||||
.name = "3420",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V5_GPIO,
|
||||
},
|
||||
[LPC_3450] = {
|
||||
.name = "3450",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V5_GPIO,
|
||||
},
|
||||
[LPC_EP80579] = {
|
||||
.name = "EP80579",
|
||||
.iTCO_version = 2,
|
||||
},
|
||||
[LPC_CPT] = {
|
||||
.name = "Cougar Point",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V5_GPIO,
|
||||
},
|
||||
[LPC_CPTD] = {
|
||||
.name = "Cougar Point Desktop",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V5_GPIO,
|
||||
},
|
||||
[LPC_CPTM] = {
|
||||
.name = "Cougar Point Mobile",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V5_GPIO,
|
||||
},
|
||||
[LPC_PBG] = {
|
||||
.name = "Patsburg",
|
||||
.iTCO_version = 2,
|
||||
},
|
||||
[LPC_DH89XXCC] = {
|
||||
.name = "DH89xxCC",
|
||||
.iTCO_version = 2,
|
||||
},
|
||||
[LPC_PPT] = {
|
||||
.name = "Panther Point",
|
||||
.iTCO_version = 2,
|
||||
},
|
||||
[LPC_LPT] = {
|
||||
.name = "Lynx Point",
|
||||
.iTCO_version = 2,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -666,12 +759,88 @@ gpio_done:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int __devinit lpc_ich_init_wdt(struct pci_dev *dev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
u32 base_addr_cfg;
|
||||
u32 base_addr;
|
||||
int ret;
|
||||
bool acpi_conflict = false;
|
||||
struct resource *res;
|
||||
|
||||
/* Setup power management base register */
|
||||
pci_read_config_dword(dev, ACPIBASE, &base_addr_cfg);
|
||||
base_addr = base_addr_cfg & 0x0000ff80;
|
||||
if (!base_addr) {
|
||||
dev_err(&dev->dev, "I/O space for ACPI uninitialized\n");
|
||||
ret = -ENODEV;
|
||||
goto wdt_done;
|
||||
}
|
||||
|
||||
res = wdt_io_res(ICH_RES_IO_TCO);
|
||||
res->start = base_addr + ACPIBASE_TCO_OFF;
|
||||
res->end = base_addr + ACPIBASE_TCO_END;
|
||||
ret = acpi_check_resource_conflict(res);
|
||||
if (ret) {
|
||||
acpi_conflict = true;
|
||||
goto wdt_done;
|
||||
}
|
||||
|
||||
res = wdt_io_res(ICH_RES_IO_SMI);
|
||||
res->start = base_addr + ACPIBASE_SMI_OFF;
|
||||
res->end = base_addr + ACPIBASE_SMI_END;
|
||||
ret = acpi_check_resource_conflict(res);
|
||||
if (ret) {
|
||||
acpi_conflict = true;
|
||||
goto wdt_done;
|
||||
}
|
||||
lpc_ich_enable_acpi_space(dev);
|
||||
|
||||
/*
|
||||
* Get the Memory-Mapped GCS register. To get access to it
|
||||
* we have to read RCBA from PCI Config space 0xf0 and use
|
||||
* it as base. GCS = RCBA + ICH6_GCS(0x3410).
|
||||
*/
|
||||
if (lpc_chipset_info[id->driver_data].iTCO_version == 2) {
|
||||
pci_read_config_dword(dev, RCBABASE, &base_addr_cfg);
|
||||
base_addr = base_addr_cfg & 0xffffc000;
|
||||
if (!(base_addr_cfg & 1)) {
|
||||
pr_err("RCBA is disabled by hardware/BIOS, "
|
||||
"device disabled\n");
|
||||
ret = -ENODEV;
|
||||
goto wdt_done;
|
||||
}
|
||||
res = wdt_mem_res(ICH_RES_MEM_GCS);
|
||||
res->start = base_addr + ACPIBASE_GCS_OFF;
|
||||
res->end = base_addr + ACPIBASE_GCS_END;
|
||||
ret = acpi_check_resource_conflict(res);
|
||||
if (ret) {
|
||||
acpi_conflict = true;
|
||||
goto wdt_done;
|
||||
}
|
||||
}
|
||||
|
||||
lpc_ich_finalize_cell(&lpc_ich_cells[LPC_WDT], id);
|
||||
ret = mfd_add_devices(&dev->dev, -1, &lpc_ich_cells[LPC_WDT],
|
||||
1, NULL, 0);
|
||||
|
||||
wdt_done:
|
||||
if (acpi_conflict)
|
||||
pr_warn("Resource conflict(s) found affecting %s\n",
|
||||
lpc_ich_cells[LPC_WDT].name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devinit lpc_ich_probe(struct pci_dev *dev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
int ret;
|
||||
bool cell_added = false;
|
||||
|
||||
ret = lpc_ich_init_wdt(dev, id);
|
||||
if (!ret)
|
||||
cell_added = true;
|
||||
|
||||
ret = lpc_ich_init_gpio(dev, id);
|
||||
if (!ret)
|
||||
cell_added = true;
|
||||
|
|
|
@ -563,6 +563,7 @@ config INTEL_SCU_WATCHDOG
|
|||
config ITCO_WDT
|
||||
tristate "Intel TCO Timer/Watchdog"
|
||||
depends on (X86 || IA64) && PCI
|
||||
select LPC_ICH
|
||||
---help---
|
||||
Hardware driver for the intel TCO timer based watchdog devices.
|
||||
These drivers are included in the Intel 82801 I/O Controller
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
/* 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_start(struct resource *, unsigned int);
|
||||
extern void iTCO_vendor_pre_stop(struct resource *);
|
||||
extern void iTCO_vendor_pre_keepalive(struct resource *, unsigned int);
|
||||
extern void iTCO_vendor_pre_set_heartbeat(unsigned int);
|
||||
extern int iTCO_vendor_check_noreboot_on(void);
|
||||
#else
|
||||
|
|
|
@ -35,11 +35,6 @@
|
|||
|
||||
#include "iTCO_vendor.h"
|
||||
|
||||
/* iTCO defines */
|
||||
#define SMI_EN (acpibase + 0x30) /* SMI Control and Enable Register */
|
||||
#define TCOBASE (acpibase + 0x60) /* TCO base address */
|
||||
#define TCO1_STS (TCOBASE + 0x04) /* TCO1 Status Register */
|
||||
|
||||
/* List of vendor support modes */
|
||||
/* SuperMicro Pentium 3 Era 370SSE+-OEM1/P3TSSE */
|
||||
#define SUPERMICRO_OLD_BOARD 1
|
||||
|
@ -82,24 +77,24 @@ MODULE_PARM_DESC(vendorsupport, "iTCO vendor specific support mode, default="
|
|||
* 20.6 seconds.
|
||||
*/
|
||||
|
||||
static void supermicro_old_pre_start(unsigned long acpibase)
|
||||
static void supermicro_old_pre_start(struct resource *smires)
|
||||
{
|
||||
unsigned long val32;
|
||||
|
||||
/* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI# */
|
||||
val32 = inl(SMI_EN);
|
||||
val32 = inl(smires->start);
|
||||
val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */
|
||||
outl(val32, SMI_EN); /* Needed to activate watchdog */
|
||||
outl(val32, smires->start); /* Needed to activate watchdog */
|
||||
}
|
||||
|
||||
static void supermicro_old_pre_stop(unsigned long acpibase)
|
||||
static void supermicro_old_pre_stop(struct resource *smires)
|
||||
{
|
||||
unsigned long val32;
|
||||
|
||||
/* Bit 13: TCO_EN -> 1 = Enables the TCO logic to generate SMI# */
|
||||
val32 = inl(SMI_EN);
|
||||
val32 = inl(smires->start);
|
||||
val32 |= 0x00002000; /* Turn on SMI clearing watchdog */
|
||||
outl(val32, SMI_EN); /* Needed to deactivate watchdog */
|
||||
outl(val32, smires->start); /* Needed to deactivate watchdog */
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -270,66 +265,66 @@ static void supermicro_new_pre_set_heartbeat(unsigned int heartbeat)
|
|||
* Don't use this fix if you don't need to!!!
|
||||
*/
|
||||
|
||||
static void broken_bios_start(unsigned long acpibase)
|
||||
static void broken_bios_start(struct resource *smires)
|
||||
{
|
||||
unsigned long val32;
|
||||
|
||||
val32 = inl(SMI_EN);
|
||||
val32 = inl(smires->start);
|
||||
/* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI#
|
||||
Bit 0: GBL_SMI_EN -> 0 = No SMI# will be generated by ICH. */
|
||||
val32 &= 0xffffdffe;
|
||||
outl(val32, SMI_EN);
|
||||
outl(val32, smires->start);
|
||||
}
|
||||
|
||||
static void broken_bios_stop(unsigned long acpibase)
|
||||
static void broken_bios_stop(struct resource *smires)
|
||||
{
|
||||
unsigned long val32;
|
||||
|
||||
val32 = inl(SMI_EN);
|
||||
val32 = inl(smires->start);
|
||||
/* Bit 13: TCO_EN -> 1 = Enables TCO logic generating an SMI#
|
||||
Bit 0: GBL_SMI_EN -> 1 = Turn global SMI on again. */
|
||||
val32 |= 0x00002001;
|
||||
outl(val32, SMI_EN);
|
||||
outl(val32, smires->start);
|
||||
}
|
||||
|
||||
/*
|
||||
* Generic Support Functions
|
||||
*/
|
||||
|
||||
void iTCO_vendor_pre_start(unsigned long acpibase,
|
||||
void iTCO_vendor_pre_start(struct resource *smires,
|
||||
unsigned int heartbeat)
|
||||
{
|
||||
switch (vendorsupport) {
|
||||
case SUPERMICRO_OLD_BOARD:
|
||||
supermicro_old_pre_start(acpibase);
|
||||
supermicro_old_pre_start(smires);
|
||||
break;
|
||||
case SUPERMICRO_NEW_BOARD:
|
||||
supermicro_new_pre_start(heartbeat);
|
||||
break;
|
||||
case BROKEN_BIOS:
|
||||
broken_bios_start(acpibase);
|
||||
broken_bios_start(smires);
|
||||
break;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(iTCO_vendor_pre_start);
|
||||
|
||||
void iTCO_vendor_pre_stop(unsigned long acpibase)
|
||||
void iTCO_vendor_pre_stop(struct resource *smires)
|
||||
{
|
||||
switch (vendorsupport) {
|
||||
case SUPERMICRO_OLD_BOARD:
|
||||
supermicro_old_pre_stop(acpibase);
|
||||
supermicro_old_pre_stop(smires);
|
||||
break;
|
||||
case SUPERMICRO_NEW_BOARD:
|
||||
supermicro_new_pre_stop();
|
||||
break;
|
||||
case BROKEN_BIOS:
|
||||
broken_bios_stop(acpibase);
|
||||
broken_bios_stop(smires);
|
||||
break;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(iTCO_vendor_pre_stop);
|
||||
|
||||
void iTCO_vendor_pre_keepalive(unsigned long acpibase, unsigned int heartbeat)
|
||||
void iTCO_vendor_pre_keepalive(struct resource *smires, unsigned int heartbeat)
|
||||
{
|
||||
if (vendorsupport == SUPERMICRO_NEW_BOARD)
|
||||
supermicro_new_pre_set_heartbeat(heartbeat);
|
||||
|
|
|
@ -66,316 +66,16 @@
|
|||
#include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */
|
||||
#include <linux/uaccess.h> /* For copy_to_user/put_user/... */
|
||||
#include <linux/io.h> /* For inb/outb/... */
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/lpc_ich.h>
|
||||
|
||||
#include "iTCO_vendor.h"
|
||||
|
||||
/* 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_631XESB, /* 631xESB/632xESB */
|
||||
TCO_ICH7, /* ICH7 & ICH7R */
|
||||
TCO_ICH7DH, /* ICH7DH */
|
||||
TCO_ICH7M, /* ICH7-M & ICH7-U */
|
||||
TCO_ICH7MDH, /* ICH7-M DH */
|
||||
TCO_NM10, /* NM10 */
|
||||
TCO_ICH8, /* ICH8 & ICH8R */
|
||||
TCO_ICH8DH, /* ICH8DH */
|
||||
TCO_ICH8DO, /* ICH8DO */
|
||||
TCO_ICH8M, /* ICH8M */
|
||||
TCO_ICH8ME, /* ICH8M-E */
|
||||
TCO_ICH9, /* ICH9 */
|
||||
TCO_ICH9R, /* ICH9R */
|
||||
TCO_ICH9DH, /* ICH9DH */
|
||||
TCO_ICH9DO, /* ICH9DO */
|
||||
TCO_ICH9M, /* ICH9M */
|
||||
TCO_ICH9ME, /* ICH9M-E */
|
||||
TCO_ICH10, /* ICH10 */
|
||||
TCO_ICH10R, /* ICH10R */
|
||||
TCO_ICH10D, /* ICH10D */
|
||||
TCO_ICH10DO, /* ICH10DO */
|
||||
TCO_PCH, /* PCH Desktop Full Featured */
|
||||
TCO_PCHM, /* PCH Mobile Full Featured */
|
||||
TCO_P55, /* P55 */
|
||||
TCO_PM55, /* PM55 */
|
||||
TCO_H55, /* H55 */
|
||||
TCO_QM57, /* QM57 */
|
||||
TCO_H57, /* H57 */
|
||||
TCO_HM55, /* HM55 */
|
||||
TCO_Q57, /* Q57 */
|
||||
TCO_HM57, /* HM57 */
|
||||
TCO_PCHMSFF, /* PCH Mobile SFF Full Featured */
|
||||
TCO_QS57, /* QS57 */
|
||||
TCO_3400, /* 3400 */
|
||||
TCO_3420, /* 3420 */
|
||||
TCO_3450, /* 3450 */
|
||||
TCO_EP80579, /* EP80579 */
|
||||
TCO_CPT, /* Cougar Point */
|
||||
TCO_CPTD, /* Cougar Point Desktop */
|
||||
TCO_CPTM, /* Cougar Point Mobile */
|
||||
TCO_PBG, /* Patsburg */
|
||||
TCO_DH89XXCC, /* DH89xxCC */
|
||||
TCO_PPT, /* Panther Point */
|
||||
TCO_LPT, /* Lynx Point */
|
||||
};
|
||||
|
||||
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},
|
||||
{"631xESB/632xESB", 2},
|
||||
{"ICH7 or ICH7R", 2},
|
||||
{"ICH7DH", 2},
|
||||
{"ICH7-M or ICH7-U", 2},
|
||||
{"ICH7-M DH", 2},
|
||||
{"NM10", 2},
|
||||
{"ICH8 or ICH8R", 2},
|
||||
{"ICH8DH", 2},
|
||||
{"ICH8DO", 2},
|
||||
{"ICH8M", 2},
|
||||
{"ICH8M-E", 2},
|
||||
{"ICH9", 2},
|
||||
{"ICH9R", 2},
|
||||
{"ICH9DH", 2},
|
||||
{"ICH9DO", 2},
|
||||
{"ICH9M", 2},
|
||||
{"ICH9M-E", 2},
|
||||
{"ICH10", 2},
|
||||
{"ICH10R", 2},
|
||||
{"ICH10D", 2},
|
||||
{"ICH10DO", 2},
|
||||
{"PCH Desktop Full Featured", 2},
|
||||
{"PCH Mobile Full Featured", 2},
|
||||
{"P55", 2},
|
||||
{"PM55", 2},
|
||||
{"H55", 2},
|
||||
{"QM57", 2},
|
||||
{"H57", 2},
|
||||
{"HM55", 2},
|
||||
{"Q57", 2},
|
||||
{"HM57", 2},
|
||||
{"PCH Mobile SFF Full Featured", 2},
|
||||
{"QS57", 2},
|
||||
{"3400", 2},
|
||||
{"3420", 2},
|
||||
{"3450", 2},
|
||||
{"EP80579", 2},
|
||||
{"Cougar Point", 2},
|
||||
{"Cougar Point Desktop", 2},
|
||||
{"Cougar Point Mobile", 2},
|
||||
{"Patsburg", 2},
|
||||
{"DH89xxCC", 2},
|
||||
{"Panther Point", 2},
|
||||
{"Lynx Point", 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 DEFINE_PCI_DEVICE_TABLE(iTCO_wdt_pci_tbl) = {
|
||||
{ PCI_VDEVICE(INTEL, 0x2410), TCO_ICH},
|
||||
{ PCI_VDEVICE(INTEL, 0x2420), TCO_ICH0},
|
||||
{ PCI_VDEVICE(INTEL, 0x2440), TCO_ICH2},
|
||||
{ PCI_VDEVICE(INTEL, 0x244c), TCO_ICH2M},
|
||||
{ PCI_VDEVICE(INTEL, 0x2480), TCO_ICH3},
|
||||
{ PCI_VDEVICE(INTEL, 0x248c), TCO_ICH3M},
|
||||
{ PCI_VDEVICE(INTEL, 0x24c0), TCO_ICH4},
|
||||
{ PCI_VDEVICE(INTEL, 0x24cc), TCO_ICH4M},
|
||||
{ PCI_VDEVICE(INTEL, 0x2450), TCO_CICH},
|
||||
{ PCI_VDEVICE(INTEL, 0x24d0), TCO_ICH5},
|
||||
{ PCI_VDEVICE(INTEL, 0x25a1), TCO_6300ESB},
|
||||
{ PCI_VDEVICE(INTEL, 0x2640), TCO_ICH6},
|
||||
{ PCI_VDEVICE(INTEL, 0x2641), TCO_ICH6M},
|
||||
{ PCI_VDEVICE(INTEL, 0x2642), TCO_ICH6W},
|
||||
{ PCI_VDEVICE(INTEL, 0x2670), TCO_631XESB},
|
||||
{ PCI_VDEVICE(INTEL, 0x2671), TCO_631XESB},
|
||||
{ PCI_VDEVICE(INTEL, 0x2672), TCO_631XESB},
|
||||
{ PCI_VDEVICE(INTEL, 0x2673), TCO_631XESB},
|
||||
{ PCI_VDEVICE(INTEL, 0x2674), TCO_631XESB},
|
||||
{ PCI_VDEVICE(INTEL, 0x2675), TCO_631XESB},
|
||||
{ PCI_VDEVICE(INTEL, 0x2676), TCO_631XESB},
|
||||
{ PCI_VDEVICE(INTEL, 0x2677), TCO_631XESB},
|
||||
{ PCI_VDEVICE(INTEL, 0x2678), TCO_631XESB},
|
||||
{ PCI_VDEVICE(INTEL, 0x2679), TCO_631XESB},
|
||||
{ PCI_VDEVICE(INTEL, 0x267a), TCO_631XESB},
|
||||
{ PCI_VDEVICE(INTEL, 0x267b), TCO_631XESB},
|
||||
{ PCI_VDEVICE(INTEL, 0x267c), TCO_631XESB},
|
||||
{ PCI_VDEVICE(INTEL, 0x267d), TCO_631XESB},
|
||||
{ PCI_VDEVICE(INTEL, 0x267e), TCO_631XESB},
|
||||
{ PCI_VDEVICE(INTEL, 0x267f), TCO_631XESB},
|
||||
{ PCI_VDEVICE(INTEL, 0x27b8), TCO_ICH7},
|
||||
{ PCI_VDEVICE(INTEL, 0x27b0), TCO_ICH7DH},
|
||||
{ PCI_VDEVICE(INTEL, 0x27b9), TCO_ICH7M},
|
||||
{ PCI_VDEVICE(INTEL, 0x27bd), TCO_ICH7MDH},
|
||||
{ PCI_VDEVICE(INTEL, 0x27bc), TCO_NM10},
|
||||
{ PCI_VDEVICE(INTEL, 0x2810), TCO_ICH8},
|
||||
{ PCI_VDEVICE(INTEL, 0x2812), TCO_ICH8DH},
|
||||
{ PCI_VDEVICE(INTEL, 0x2814), TCO_ICH8DO},
|
||||
{ PCI_VDEVICE(INTEL, 0x2815), TCO_ICH8M},
|
||||
{ PCI_VDEVICE(INTEL, 0x2811), TCO_ICH8ME},
|
||||
{ PCI_VDEVICE(INTEL, 0x2918), TCO_ICH9},
|
||||
{ PCI_VDEVICE(INTEL, 0x2916), TCO_ICH9R},
|
||||
{ PCI_VDEVICE(INTEL, 0x2912), TCO_ICH9DH},
|
||||
{ PCI_VDEVICE(INTEL, 0x2914), TCO_ICH9DO},
|
||||
{ PCI_VDEVICE(INTEL, 0x2919), TCO_ICH9M},
|
||||
{ PCI_VDEVICE(INTEL, 0x2917), TCO_ICH9ME},
|
||||
{ PCI_VDEVICE(INTEL, 0x3a18), TCO_ICH10},
|
||||
{ PCI_VDEVICE(INTEL, 0x3a16), TCO_ICH10R},
|
||||
{ PCI_VDEVICE(INTEL, 0x3a1a), TCO_ICH10D},
|
||||
{ PCI_VDEVICE(INTEL, 0x3a14), TCO_ICH10DO},
|
||||
{ PCI_VDEVICE(INTEL, 0x3b00), TCO_PCH},
|
||||
{ PCI_VDEVICE(INTEL, 0x3b01), TCO_PCHM},
|
||||
{ PCI_VDEVICE(INTEL, 0x3b02), TCO_P55},
|
||||
{ PCI_VDEVICE(INTEL, 0x3b03), TCO_PM55},
|
||||
{ PCI_VDEVICE(INTEL, 0x3b06), TCO_H55},
|
||||
{ PCI_VDEVICE(INTEL, 0x3b07), TCO_QM57},
|
||||
{ PCI_VDEVICE(INTEL, 0x3b08), TCO_H57},
|
||||
{ PCI_VDEVICE(INTEL, 0x3b09), TCO_HM55},
|
||||
{ PCI_VDEVICE(INTEL, 0x3b0a), TCO_Q57},
|
||||
{ PCI_VDEVICE(INTEL, 0x3b0b), TCO_HM57},
|
||||
{ PCI_VDEVICE(INTEL, 0x3b0d), TCO_PCHMSFF},
|
||||
{ PCI_VDEVICE(INTEL, 0x3b0f), TCO_QS57},
|
||||
{ PCI_VDEVICE(INTEL, 0x3b12), TCO_3400},
|
||||
{ PCI_VDEVICE(INTEL, 0x3b14), TCO_3420},
|
||||
{ PCI_VDEVICE(INTEL, 0x3b16), TCO_3450},
|
||||
{ PCI_VDEVICE(INTEL, 0x5031), TCO_EP80579},
|
||||
{ PCI_VDEVICE(INTEL, 0x1c41), TCO_CPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1c42), TCO_CPTD},
|
||||
{ PCI_VDEVICE(INTEL, 0x1c43), TCO_CPTM},
|
||||
{ PCI_VDEVICE(INTEL, 0x1c44), TCO_CPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1c45), TCO_CPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1c46), TCO_CPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1c47), TCO_CPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1c48), TCO_CPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1c49), TCO_CPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1c4a), TCO_CPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1c4b), TCO_CPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1c4c), TCO_CPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1c4d), TCO_CPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1c4e), TCO_CPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1c4f), TCO_CPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1c50), TCO_CPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1c51), TCO_CPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1c52), TCO_CPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1c53), TCO_CPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1c54), TCO_CPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1c55), TCO_CPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1c56), TCO_CPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1c57), TCO_CPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1c58), TCO_CPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1c59), TCO_CPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1c5a), TCO_CPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1c5b), TCO_CPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1c5c), TCO_CPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1c5d), TCO_CPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1c5e), TCO_CPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1c5f), TCO_CPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1d40), TCO_PBG},
|
||||
{ PCI_VDEVICE(INTEL, 0x1d41), TCO_PBG},
|
||||
{ PCI_VDEVICE(INTEL, 0x2310), TCO_DH89XXCC},
|
||||
{ PCI_VDEVICE(INTEL, 0x1e40), TCO_PPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1e41), TCO_PPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1e42), TCO_PPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1e43), TCO_PPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1e44), TCO_PPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1e45), TCO_PPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1e46), TCO_PPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1e47), TCO_PPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1e48), TCO_PPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1e49), TCO_PPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1e4a), TCO_PPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1e4b), TCO_PPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1e4c), TCO_PPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1e4d), TCO_PPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1e4e), TCO_PPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1e4f), TCO_PPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1e50), TCO_PPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1e51), TCO_PPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1e52), TCO_PPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1e53), TCO_PPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1e54), TCO_PPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1e55), TCO_PPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1e56), TCO_PPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1e57), TCO_PPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1e58), TCO_PPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1e59), TCO_PPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1e5a), TCO_PPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1e5b), TCO_PPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1e5c), TCO_PPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1e5d), TCO_PPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1e5e), TCO_PPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x1e5f), TCO_PPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x8c40), TCO_LPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x8c41), TCO_LPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x8c42), TCO_LPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x8c43), TCO_LPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x8c44), TCO_LPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x8c45), TCO_LPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x8c46), TCO_LPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x8c47), TCO_LPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x8c48), TCO_LPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x8c49), TCO_LPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x8c4a), TCO_LPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x8c4b), TCO_LPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x8c4c), TCO_LPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x8c4d), TCO_LPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x8c4e), TCO_LPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x8c4f), TCO_LPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x8c50), TCO_LPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x8c51), TCO_LPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x8c52), TCO_LPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x8c53), TCO_LPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x8c54), TCO_LPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x8c55), TCO_LPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x8c56), TCO_LPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x8c57), TCO_LPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x8c58), TCO_LPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x8c59), TCO_LPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x8c5a), TCO_LPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x8c5b), TCO_LPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x8c5c), TCO_LPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x8c5d), TCO_LPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x8c5e), TCO_LPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x8c5f), TCO_LPT},
|
||||
{ 0, }, /* End of list */
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, iTCO_wdt_pci_tbl);
|
||||
|
||||
/* Address definitions for the TCO */
|
||||
/* TCO base address */
|
||||
#define TCOBASE (iTCO_wdt_private.ACPIBASE + 0x60)
|
||||
#define TCOBASE (iTCO_wdt_private.tco_res->start)
|
||||
/* SMI Control and Enable Register */
|
||||
#define SMI_EN (iTCO_wdt_private.ACPIBASE + 0x30)
|
||||
#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 */
|
||||
|
@ -393,19 +93,18 @@ static char expect_release;
|
|||
static struct { /* this is private data for the iTCO_wdt device */
|
||||
/* TCO version/generation */
|
||||
unsigned int iTCO_version;
|
||||
/* The device's ACPIBASE address (TCOBASE = ACPIBASE+0x60) */
|
||||
unsigned long ACPIBASE;
|
||||
struct resource *tco_res;
|
||||
struct resource *smi_res;
|
||||
struct resource *gcs_res;
|
||||
/* NO_REBOOT flag is Memory-Mapped GCS register bit 5 (TCO version 2)*/
|
||||
unsigned long __iomem *gcs;
|
||||
/* the lock for io operations */
|
||||
spinlock_t io_lock;
|
||||
struct platform_device *dev;
|
||||
/* the PCI-device */
|
||||
struct pci_dev *pdev;
|
||||
} iTCO_wdt_private;
|
||||
|
||||
/* the watchdog platform device */
|
||||
static struct platform_device *iTCO_wdt_platform_device;
|
||||
|
||||
/* module parameters */
|
||||
#define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat */
|
||||
static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */
|
||||
|
@ -485,7 +184,7 @@ static int iTCO_wdt_start(void)
|
|||
|
||||
spin_lock(&iTCO_wdt_private.io_lock);
|
||||
|
||||
iTCO_vendor_pre_start(iTCO_wdt_private.ACPIBASE, heartbeat);
|
||||
iTCO_vendor_pre_start(iTCO_wdt_private.smi_res, heartbeat);
|
||||
|
||||
/* disable chipset's NO_REBOOT bit */
|
||||
if (iTCO_wdt_unset_NO_REBOOT_bit()) {
|
||||
|
@ -519,7 +218,7 @@ static int iTCO_wdt_stop(void)
|
|||
|
||||
spin_lock(&iTCO_wdt_private.io_lock);
|
||||
|
||||
iTCO_vendor_pre_stop(iTCO_wdt_private.ACPIBASE);
|
||||
iTCO_vendor_pre_stop(iTCO_wdt_private.smi_res);
|
||||
|
||||
/* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */
|
||||
val = inw(TCO1_CNT);
|
||||
|
@ -541,7 +240,7 @@ static int iTCO_wdt_keepalive(void)
|
|||
{
|
||||
spin_lock(&iTCO_wdt_private.io_lock);
|
||||
|
||||
iTCO_vendor_pre_keepalive(iTCO_wdt_private.ACPIBASE, heartbeat);
|
||||
iTCO_vendor_pre_keepalive(iTCO_wdt_private.smi_res, heartbeat);
|
||||
|
||||
/* Reload the timer by writing to the TCO Timer Counter register */
|
||||
if (iTCO_wdt_private.iTCO_version == 2)
|
||||
|
@ -786,83 +485,120 @@ static struct miscdevice iTCO_wdt_miscdev = {
|
|||
* Init & exit routines
|
||||
*/
|
||||
|
||||
static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
|
||||
const struct pci_device_id *ent, struct platform_device *dev)
|
||||
static void __devexit iTCO_wdt_cleanup(void)
|
||||
{
|
||||
int ret;
|
||||
u32 base_address;
|
||||
unsigned long RCBA;
|
||||
/* Stop the timer before we leave */
|
||||
if (!nowayout)
|
||||
iTCO_wdt_stop();
|
||||
|
||||
/* Deregister */
|
||||
misc_deregister(&iTCO_wdt_miscdev);
|
||||
|
||||
/* release resources */
|
||||
release_region(iTCO_wdt_private.tco_res->start,
|
||||
resource_size(iTCO_wdt_private.tco_res));
|
||||
release_region(iTCO_wdt_private.smi_res->start,
|
||||
resource_size(iTCO_wdt_private.smi_res));
|
||||
if (iTCO_wdt_private.iTCO_version == 2) {
|
||||
iounmap(iTCO_wdt_private.gcs);
|
||||
release_mem_region(iTCO_wdt_private.gcs_res->start,
|
||||
resource_size(iTCO_wdt_private.gcs_res));
|
||||
}
|
||||
|
||||
iTCO_wdt_private.tco_res = NULL;
|
||||
iTCO_wdt_private.smi_res = NULL;
|
||||
iTCO_wdt_private.gcs_res = NULL;
|
||||
iTCO_wdt_private.gcs = NULL;
|
||||
}
|
||||
|
||||
static int __devinit iTCO_wdt_probe(struct platform_device *dev)
|
||||
{
|
||||
int ret = -ENODEV;
|
||||
unsigned long val32;
|
||||
struct lpc_ich_info *ich_info = dev->dev.platform_data;
|
||||
|
||||
if (!ich_info)
|
||||
goto out;
|
||||
|
||||
spin_lock_init(&iTCO_wdt_private.io_lock);
|
||||
|
||||
iTCO_wdt_private.tco_res =
|
||||
platform_get_resource(dev, IORESOURCE_IO, ICH_RES_IO_TCO);
|
||||
if (!iTCO_wdt_private.tco_res)
|
||||
goto out;
|
||||
|
||||
iTCO_wdt_private.smi_res =
|
||||
platform_get_resource(dev, IORESOURCE_IO, ICH_RES_IO_SMI);
|
||||
if (!iTCO_wdt_private.smi_res)
|
||||
goto out;
|
||||
|
||||
iTCO_wdt_private.iTCO_version = ich_info->iTCO_version;
|
||||
iTCO_wdt_private.dev = dev;
|
||||
iTCO_wdt_private.pdev = to_pci_dev(dev->dev.parent);
|
||||
|
||||
/*
|
||||
* Find the ACPI/PM base I/O address which is the base
|
||||
* for the TCO registers (TCOBASE=ACPIBASE + 0x60)
|
||||
* ACPIBASE is bits [15:7] from 0x40-0x43
|
||||
* Get the Memory-Mapped GCS register, we need it for the
|
||||
* NO_REBOOT flag (TCO v2).
|
||||
*/
|
||||
pci_read_config_dword(pdev, 0x40, &base_address);
|
||||
base_address &= 0x0000ff80;
|
||||
if (base_address == 0x00000000) {
|
||||
/* Something's wrong here, ACPIBASE has to be set */
|
||||
pr_err("failed to get TCOBASE address, device disabled by hardware/BIOS\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
iTCO_wdt_private.iTCO_version =
|
||||
iTCO_chipset_info[ent->driver_data].iTCO_version;
|
||||
iTCO_wdt_private.ACPIBASE = base_address;
|
||||
iTCO_wdt_private.pdev = pdev;
|
||||
|
||||
/* Get the Memory-Mapped GCS register, we need it for the
|
||||
NO_REBOOT flag (TCO v2). To get access to it you have to
|
||||
read RCBA from PCI Config space 0xf0 and use it as base.
|
||||
GCS = RCBA + ICH6_GCS(0x3410). */
|
||||
if (iTCO_wdt_private.iTCO_version == 2) {
|
||||
pci_read_config_dword(pdev, 0xf0, &base_address);
|
||||
if ((base_address & 1) == 0) {
|
||||
pr_err("RCBA is disabled by hardware/BIOS, device disabled\n");
|
||||
ret = -ENODEV;
|
||||
iTCO_wdt_private.gcs_res = platform_get_resource(dev,
|
||||
IORESOURCE_MEM,
|
||||
ICH_RES_MEM_GCS);
|
||||
|
||||
if (!iTCO_wdt_private.gcs_res)
|
||||
goto out;
|
||||
|
||||
if (!request_mem_region(iTCO_wdt_private.gcs_res->start,
|
||||
resource_size(iTCO_wdt_private.gcs_res), dev->name)) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
RCBA = base_address & 0xffffc000;
|
||||
iTCO_wdt_private.gcs = ioremap((RCBA + 0x3410), 4);
|
||||
iTCO_wdt_private.gcs = ioremap(iTCO_wdt_private.gcs_res->start,
|
||||
resource_size(iTCO_wdt_private.gcs_res));
|
||||
if (!iTCO_wdt_private.gcs) {
|
||||
ret = -EIO;
|
||||
goto unreg_gcs;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check chipset's NO_REBOOT bit */
|
||||
if (iTCO_wdt_unset_NO_REBOOT_bit() && iTCO_vendor_check_noreboot_on()) {
|
||||
pr_info("unable to reset NO_REBOOT flag, device disabled by hardware/BIOS\n");
|
||||
ret = -ENODEV; /* Cannot reset NO_REBOOT bit */
|
||||
goto out_unmap;
|
||||
goto unmap_gcs;
|
||||
}
|
||||
|
||||
/* Set the NO_REBOOT bit to prevent later reboots, just for sure */
|
||||
iTCO_wdt_set_NO_REBOOT_bit();
|
||||
|
||||
/* The TCO logic uses the TCO_EN bit in the SMI_EN register */
|
||||
if (!request_region(SMI_EN, 4, "iTCO_wdt")) {
|
||||
pr_err("I/O address 0x%04lx already in use, device disabled\n",
|
||||
if (!request_region(iTCO_wdt_private.smi_res->start,
|
||||
resource_size(iTCO_wdt_private.smi_res), dev->name)) {
|
||||
pr_err("I/O address 0x%04llx already in use, device disabled\n",
|
||||
SMI_EN);
|
||||
ret = -EIO;
|
||||
goto out_unmap;
|
||||
ret = -EBUSY;
|
||||
goto unmap_gcs;
|
||||
}
|
||||
if (turn_SMI_watchdog_clear_off >= iTCO_wdt_private.iTCO_version) {
|
||||
/* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI# */
|
||||
/*
|
||||
* Bit 13: TCO_EN -> 0
|
||||
* Disables TCO logic generating an SMI#
|
||||
*/
|
||||
val32 = inl(SMI_EN);
|
||||
val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */
|
||||
outl(val32, SMI_EN);
|
||||
}
|
||||
|
||||
/* The TCO I/O registers reside in a 32-byte range pointed to
|
||||
by the TCOBASE value */
|
||||
if (!request_region(TCOBASE, 0x20, "iTCO_wdt")) {
|
||||
pr_err("I/O address 0x%04lx already in use, device disabled\n",
|
||||
if (!request_region(iTCO_wdt_private.tco_res->start,
|
||||
resource_size(iTCO_wdt_private.tco_res), dev->name)) {
|
||||
pr_err("I/O address 0x%04llx already in use, device disabled\n",
|
||||
TCOBASE);
|
||||
ret = -EIO;
|
||||
goto unreg_smi_en;
|
||||
ret = -EBUSY;
|
||||
goto unreg_smi;
|
||||
}
|
||||
|
||||
pr_info("Found a %s TCO device (Version=%d, TCOBASE=0x%04lx)\n",
|
||||
iTCO_chipset_info[ent->driver_data].name,
|
||||
iTCO_chipset_info[ent->driver_data].iTCO_version,
|
||||
TCOBASE);
|
||||
pr_info("Found a %s TCO device (Version=%d, TCOBASE=0x%04llx)\n",
|
||||
ich_info->name, ich_info->iTCO_version, TCOBASE);
|
||||
|
||||
/* Clear out the (probably old) status */
|
||||
outw(0x0008, TCO1_STS); /* Clear the Time Out Status bit */
|
||||
|
@ -883,7 +619,7 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
|
|||
if (ret != 0) {
|
||||
pr_err("cannot register miscdev on minor=%d (err=%d)\n",
|
||||
WATCHDOG_MINOR, ret);
|
||||
goto unreg_region;
|
||||
goto unreg_tco;
|
||||
}
|
||||
|
||||
pr_info("initialized. heartbeat=%d sec (nowayout=%d)\n",
|
||||
|
@ -891,62 +627,31 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
|
|||
|
||||
return 0;
|
||||
|
||||
unreg_region:
|
||||
release_region(TCOBASE, 0x20);
|
||||
unreg_smi_en:
|
||||
release_region(SMI_EN, 4);
|
||||
out_unmap:
|
||||
unreg_tco:
|
||||
release_region(iTCO_wdt_private.tco_res->start,
|
||||
resource_size(iTCO_wdt_private.tco_res));
|
||||
unreg_smi:
|
||||
release_region(iTCO_wdt_private.smi_res->start,
|
||||
resource_size(iTCO_wdt_private.smi_res));
|
||||
unmap_gcs:
|
||||
if (iTCO_wdt_private.iTCO_version == 2)
|
||||
iounmap(iTCO_wdt_private.gcs);
|
||||
unreg_gcs:
|
||||
if (iTCO_wdt_private.iTCO_version == 2)
|
||||
release_mem_region(iTCO_wdt_private.gcs_res->start,
|
||||
resource_size(iTCO_wdt_private.gcs_res));
|
||||
out:
|
||||
iTCO_wdt_private.ACPIBASE = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __devexit iTCO_wdt_cleanup(void)
|
||||
{
|
||||
/* Stop the timer before we leave */
|
||||
if (!nowayout)
|
||||
iTCO_wdt_stop();
|
||||
|
||||
/* Deregister */
|
||||
misc_deregister(&iTCO_wdt_miscdev);
|
||||
release_region(TCOBASE, 0x20);
|
||||
release_region(SMI_EN, 4);
|
||||
if (iTCO_wdt_private.iTCO_version == 2)
|
||||
iounmap(iTCO_wdt_private.gcs);
|
||||
pci_dev_put(iTCO_wdt_private.pdev);
|
||||
iTCO_wdt_private.ACPIBASE = 0;
|
||||
}
|
||||
|
||||
static int __devinit iTCO_wdt_probe(struct platform_device *dev)
|
||||
{
|
||||
int ret = -ENODEV;
|
||||
int found = 0;
|
||||
struct pci_dev *pdev = NULL;
|
||||
const struct pci_device_id *ent;
|
||||
|
||||
spin_lock_init(&iTCO_wdt_private.io_lock);
|
||||
|
||||
for_each_pci_dev(pdev) {
|
||||
ent = pci_match_id(iTCO_wdt_pci_tbl, pdev);
|
||||
if (ent) {
|
||||
found++;
|
||||
ret = iTCO_wdt_init(pdev, ent, dev);
|
||||
if (!ret)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
pr_info("No device detected\n");
|
||||
iTCO_wdt_private.tco_res = NULL;
|
||||
iTCO_wdt_private.smi_res = NULL;
|
||||
iTCO_wdt_private.gcs_res = NULL;
|
||||
iTCO_wdt_private.gcs = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit iTCO_wdt_remove(struct platform_device *dev)
|
||||
{
|
||||
if (iTCO_wdt_private.ACPIBASE)
|
||||
if (iTCO_wdt_private.tco_res || iTCO_wdt_private.smi_res)
|
||||
iTCO_wdt_cleanup();
|
||||
|
||||
return 0;
|
||||
|
@ -977,23 +682,11 @@ static int __init iTCO_wdt_init_module(void)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
iTCO_wdt_platform_device = platform_device_register_simple(DRV_NAME,
|
||||
-1, NULL, 0);
|
||||
if (IS_ERR(iTCO_wdt_platform_device)) {
|
||||
err = PTR_ERR(iTCO_wdt_platform_device);
|
||||
goto unreg_platform_driver;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
unreg_platform_driver:
|
||||
platform_driver_unregister(&iTCO_wdt_driver);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit iTCO_wdt_cleanup_module(void)
|
||||
{
|
||||
platform_device_unregister(iTCO_wdt_platform_device);
|
||||
platform_driver_unregister(&iTCO_wdt_driver);
|
||||
pr_info("Watchdog Module Unloaded\n");
|
||||
}
|
||||
|
|
|
@ -20,6 +20,12 @@
|
|||
#ifndef LPC_ICH_H
|
||||
#define LPC_ICH_H
|
||||
|
||||
/* Watchdog resources */
|
||||
#define ICH_RES_IO_TCO 0
|
||||
#define ICH_RES_IO_SMI 1
|
||||
#define ICH_RES_MEM_OFF 2
|
||||
#define ICH_RES_MEM_GCS 0
|
||||
|
||||
/* GPIO resources */
|
||||
#define ICH_RES_GPIO 0
|
||||
#define ICH_RES_GPE0 1
|
||||
|
@ -35,6 +41,7 @@
|
|||
|
||||
struct lpc_ich_info {
|
||||
char name[32];
|
||||
unsigned int iTCO_version;
|
||||
unsigned int gpio_version;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue