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:
Aaron Sierra 2012-04-20 14:14:11 -05:00 committed by Samuel Ortiz
parent 16c5c023aa
commit 887c8ec721
7 changed files with 313 additions and 447 deletions

View File

@ -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"

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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");
}

View File

@ -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;
};