aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/watchdog
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/watchdog')
-rw-r--r--drivers/watchdog/i6300esb.c170
1 files changed, 90 insertions, 80 deletions
diff --git a/drivers/watchdog/i6300esb.c b/drivers/watchdog/i6300esb.c
index 4f4287d83c21..147462f431de 100644
--- a/drivers/watchdog/i6300esb.c
+++ b/drivers/watchdog/i6300esb.c
@@ -23,6 +23,7 @@
* Ported driver to kernel 2.6
* 20171016 Radu Rendec <rrendec@arista.com>
* Change driver to use the watchdog subsystem
+ * Add support for multiple 6300ESB devices
*/
/*
@@ -52,10 +53,10 @@
#define ESB_LOCK_REG 0x68 /* WDT lock register */
/* Memory mapped registers */
-#define ESB_TIMER1_REG (BASEADDR + 0x00)/* Timer1 value after each reset */
-#define ESB_TIMER2_REG (BASEADDR + 0x04)/* Timer2 value after each reset */
-#define ESB_GINTSR_REG (BASEADDR + 0x08)/* General Interrupt Status Register */
-#define ESB_RELOAD_REG (BASEADDR + 0x0c)/* Reload register */
+#define ESB_TIMER1_REG(w) ((w)->base + 0x00)/* Timer1 value after each reset */
+#define ESB_TIMER2_REG(w) ((w)->base + 0x04)/* Timer2 value after each reset */
+#define ESB_GINTSR_REG(w) ((w)->base + 0x08)/* General Interrupt Status Reg */
+#define ESB_RELOAD_REG(w) ((w)->base + 0x0c)/* Reload register */
/* Lock register bits */
#define ESB_WDT_FUNC (0x01 << 2) /* Watchdog functionality */
@@ -75,11 +76,7 @@
#define ESB_UNLOCK1 0x80 /* Step 1 to unlock reset registers */
#define ESB_UNLOCK2 0x86 /* Step 2 to unlock reset registers */
-/* internal variables */
-static void __iomem *BASEADDR;
-static struct pci_dev *esb_pci;
-
-/* We can only use 1 card due to the /dev/watchdog restriction */
+/* Probed devices counter; used only for printing the initial info message */
static int cards_found;
/* module parameters */
@@ -97,6 +94,15 @@ MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+/* internal variables */
+struct esb_dev {
+ struct watchdog_device wdd;
+ void __iomem *base;
+ struct pci_dev *pdev;
+};
+
+#define to_esb_dev(wptr) container_of(wptr, struct esb_dev, wdd)
+
/*
* Some i6300ESB specific functions
*/
@@ -107,35 +113,37 @@ MODULE_PARM_DESC(nowayout,
* reload register. After this the appropriate registers can be written
* to once before they need to be unlocked again.
*/
-static inline void esb_unlock_registers(void)
+static inline void esb_unlock_registers(struct esb_dev *edev)
{
- writew(ESB_UNLOCK1, ESB_RELOAD_REG);
- writew(ESB_UNLOCK2, ESB_RELOAD_REG);
+ writew(ESB_UNLOCK1, ESB_RELOAD_REG(edev));
+ writew(ESB_UNLOCK2, ESB_RELOAD_REG(edev));
}
static int esb_timer_start(struct watchdog_device *wdd)
{
+ struct esb_dev *edev = to_esb_dev(wdd);
int _wdd_nowayout = test_bit(WDOG_NO_WAY_OUT, &wdd->status);
u8 val;
- esb_unlock_registers();
- writew(ESB_WDT_RELOAD, ESB_RELOAD_REG);
+ esb_unlock_registers(edev);
+ writew(ESB_WDT_RELOAD, ESB_RELOAD_REG(edev));
/* Enable or Enable + Lock? */
val = ESB_WDT_ENABLE | (_wdd_nowayout ? ESB_WDT_LOCK : 0x00);
- pci_write_config_byte(esb_pci, ESB_LOCK_REG, val);
+ pci_write_config_byte(edev->pdev, ESB_LOCK_REG, val);
return 0;
}
static int esb_timer_stop(struct watchdog_device *wdd)
{
+ struct esb_dev *edev = to_esb_dev(wdd);
u8 val;
/* First, reset timers as suggested by the docs */
- esb_unlock_registers();
- writew(ESB_WDT_RELOAD, ESB_RELOAD_REG);
+ esb_unlock_registers(edev);
+ writew(ESB_WDT_RELOAD, ESB_RELOAD_REG(edev));
/* Then disable the WDT */
- pci_write_config_byte(esb_pci, ESB_LOCK_REG, 0x0);
- pci_read_config_byte(esb_pci, ESB_LOCK_REG, &val);
+ pci_write_config_byte(edev->pdev, ESB_LOCK_REG, 0x0);
+ pci_read_config_byte(edev->pdev, ESB_LOCK_REG, &val);
/* Returns 0 if the timer was disabled, non-zero otherwise */
return val & ESB_WDT_ENABLE;
@@ -143,8 +151,10 @@ static int esb_timer_stop(struct watchdog_device *wdd)
static int esb_timer_keepalive(struct watchdog_device *wdd)
{
- esb_unlock_registers();
- writew(ESB_WDT_RELOAD, ESB_RELOAD_REG);
+ struct esb_dev *edev = to_esb_dev(wdd);
+
+ esb_unlock_registers(edev);
+ writew(ESB_WDT_RELOAD, ESB_RELOAD_REG(edev));
/* FIXME: Do we need to flush anything here? */
return 0;
}
@@ -152,6 +162,7 @@ static int esb_timer_keepalive(struct watchdog_device *wdd)
static int esb_timer_set_heartbeat(struct watchdog_device *wdd,
unsigned int time)
{
+ struct esb_dev *edev = to_esb_dev(wdd);
u32 val;
/* We shift by 9, so if we are passed a value of 1 sec,
@@ -161,16 +172,16 @@ static int esb_timer_set_heartbeat(struct watchdog_device *wdd,
val = time << 9;
/* Write timer 1 */
- esb_unlock_registers();
- writel(val, ESB_TIMER1_REG);
+ esb_unlock_registers(edev);
+ writel(val, ESB_TIMER1_REG(edev));
/* Write timer 2 */
- esb_unlock_registers();
- writel(val, ESB_TIMER2_REG);
+ esb_unlock_registers(edev);
+ writel(val, ESB_TIMER2_REG(edev));
/* Reload */
- esb_unlock_registers();
- writew(ESB_WDT_RELOAD, ESB_RELOAD_REG);
+ esb_unlock_registers(edev);
+ writew(ESB_WDT_RELOAD, ESB_RELOAD_REG(edev));
/* FIXME: Do we need to flush everything out? */
@@ -196,14 +207,6 @@ static const struct watchdog_ops esb_ops = {
.ping = esb_timer_keepalive,
};
-static struct watchdog_device esb_dev = {
- .info = &esb_info,
- .ops = &esb_ops,
- .min_timeout = 1,
- .max_timeout = 2 * 0x03ff,
- .timeout = WATCHDOG_HEARTBEAT,
-};
-
/*
* Data for PCI driver interface
*/
@@ -217,38 +220,38 @@ MODULE_DEVICE_TABLE(pci, esb_pci_tbl);
* Init & exit routines
*/
-static unsigned char esb_getdevice(struct pci_dev *pdev)
+static unsigned char esb_getdevice(struct esb_dev *edev)
{
- if (pci_enable_device(pdev)) {
- dev_err(&pdev->dev, "failed to enable device\n");
+ if (pci_enable_device(edev->pdev)) {
+ dev_err(&edev->pdev->dev, "failed to enable device\n");
goto err_devput;
}
- if (pci_request_region(pdev, 0, ESB_MODULE_NAME)) {
- dev_err(&pdev->dev, "failed to request region\n");
+ if (pci_request_region(edev->pdev, 0, ESB_MODULE_NAME)) {
+ dev_err(&edev->pdev->dev, "failed to request region\n");
goto err_disable;
}
- BASEADDR = pci_ioremap_bar(pdev, 0);
- if (BASEADDR == NULL) {
+ edev->base = pci_ioremap_bar(edev->pdev, 0);
+ if (edev->base == NULL) {
/* Something's wrong here, BASEADDR has to be set */
- dev_err(&pdev->dev, "failed to get BASEADDR\n");
+ dev_err(&edev->pdev->dev, "failed to get BASEADDR\n");
goto err_release;
}
/* Done */
- esb_pci = pdev;
+ dev_set_drvdata(&edev->pdev->dev, edev);
return 1;
err_release:
- pci_release_region(pdev, 0);
+ pci_release_region(edev->pdev, 0);
err_disable:
- pci_disable_device(pdev);
+ pci_disable_device(edev->pdev);
err_devput:
return 0;
}
-static void esb_initdevice(void)
+static void esb_initdevice(struct esb_dev *edev)
{
u8 val1;
u16 val2;
@@ -265,33 +268,34 @@ static void esb_initdevice(void)
* any interrupts as there is not much we can do with it
* right now.
*/
- pci_write_config_word(esb_pci, ESB_CONFIG_REG, 0x0003);
+ pci_write_config_word(edev->pdev, ESB_CONFIG_REG, 0x0003);
/* Check that the WDT isn't already locked */
- pci_read_config_byte(esb_pci, ESB_LOCK_REG, &val1);
+ pci_read_config_byte(edev->pdev, ESB_LOCK_REG, &val1);
if (val1 & ESB_WDT_LOCK)
- dev_warn(&esb_pci->dev, "nowayout already set\n");
+ dev_warn(&edev->pdev->dev, "nowayout already set\n");
/* Set the timer to watchdog mode and disable it for now */
- pci_write_config_byte(esb_pci, ESB_LOCK_REG, 0x00);
+ pci_write_config_byte(edev->pdev, ESB_LOCK_REG, 0x00);
/* Check if the watchdog was previously triggered */
- esb_unlock_registers();
- val2 = readw(ESB_RELOAD_REG);
+ esb_unlock_registers(edev);
+ val2 = readw(ESB_RELOAD_REG(edev));
if (val2 & ESB_WDT_TIMEOUT)
- esb_dev.bootstatus = WDIOF_CARDRESET;
+ edev->wdd.bootstatus = WDIOF_CARDRESET;
/* Reset WDT_TIMEOUT flag and timers */
- esb_unlock_registers();
- writew((ESB_WDT_TIMEOUT | ESB_WDT_RELOAD), ESB_RELOAD_REG);
+ esb_unlock_registers(edev);
+ writew((ESB_WDT_TIMEOUT | ESB_WDT_RELOAD), ESB_RELOAD_REG(edev));
/* And set the correct timeout value */
- esb_timer_set_heartbeat(&esb_dev, esb_dev.timeout);
+ esb_timer_set_heartbeat(&edev->wdd, edev->wdd.timeout);
}
static int esb_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
+ struct esb_dev *edev;
int ret;
cards_found++;
@@ -299,26 +303,32 @@ static int esb_probe(struct pci_dev *pdev,
pr_info("Intel 6300ESB WatchDog Timer Driver v%s\n",
ESB_VERSION);
- if (cards_found > 1) {
- pr_err("This driver only supports 1 device\n");
- return -ENODEV;
- }
+ edev = devm_kzalloc(&pdev->dev, sizeof(*edev), GFP_KERNEL);
+ if (!edev)
+ return -ENOMEM;
/* Check whether or not the hardware watchdog is there */
- if (!esb_getdevice(pdev) || esb_pci == NULL)
+ edev->pdev = pdev;
+ if (!esb_getdevice(edev))
return -ENODEV;
/* Initialize the watchdog and make sure it does not run */
- if (watchdog_init_timeout(&esb_dev, heartbeat, NULL))
- pr_info("heartbeat value must be 1<heartbeat<2046, using %u\n",
- esb_dev.timeout);
- watchdog_set_nowayout(&esb_dev, nowayout);
- watchdog_stop_on_reboot(&esb_dev);
- watchdog_stop_on_unregister(&esb_dev);
- esb_initdevice();
+ edev->wdd.info = &esb_info;
+ edev->wdd.ops = &esb_ops;
+ edev->wdd.min_timeout = 1;
+ edev->wdd.max_timeout = 2 * 0x03ff;
+ edev->wdd.timeout = WATCHDOG_HEARTBEAT;
+ if (watchdog_init_timeout(&edev->wdd, heartbeat, NULL))
+ dev_info(&pdev->dev,
+ "heartbeat value must be 1<heartbeat<2046, using %u\n",
+ edev->wdd.timeout);
+ watchdog_set_nowayout(&edev->wdd, nowayout);
+ watchdog_stop_on_reboot(&edev->wdd);
+ watchdog_stop_on_unregister(&edev->wdd);
+ esb_initdevice(edev);
/* Register the watchdog so that userspace has access to it */
- ret = watchdog_register_device(&esb_dev);
+ ret = watchdog_register_device(&edev->wdd);
if (ret != 0) {
dev_err(&pdev->dev,
"cannot register watchdog device (err=%d)\n", ret);
@@ -326,24 +336,24 @@ static int esb_probe(struct pci_dev *pdev,
}
dev_info(&pdev->dev,
"initialized (0x%p). heartbeat=%d sec (nowayout=%d)\n",
- BASEADDR, esb_dev.timeout, nowayout);
+ edev->base, edev->wdd.timeout, nowayout);
return 0;
err_unmap:
- iounmap(BASEADDR);
- pci_release_region(esb_pci, 0);
- pci_disable_device(esb_pci);
- esb_pci = NULL;
+ iounmap(edev->base);
+ pci_release_region(edev->pdev, 0);
+ pci_disable_device(edev->pdev);
return ret;
}
static void esb_remove(struct pci_dev *pdev)
{
- watchdog_unregister_device(&esb_dev);
- iounmap(BASEADDR);
- pci_release_region(esb_pci, 0);
- pci_disable_device(esb_pci);
- esb_pci = NULL;
+ struct esb_dev *edev = dev_get_drvdata(&pdev->dev);
+
+ watchdog_unregister_device(&edev->wdd);
+ iounmap(edev->base);
+ pci_release_region(edev->pdev, 0);
+ pci_disable_device(edev->pdev);
}
static struct pci_driver esb_driver = {

Privacy Policy