cregit-Linux how code gets into the kernel

Release 4.11 drivers/watchdog/via_wdt.c

Directory: drivers/watchdog
/*
 * VIA Chipset Watchdog Driver
 *
 * Copyright (C) 2011 Sigfox
 * License terms: GNU General Public License (GPL) version 2
 * Author: Marc Vertes <marc.vertes@sigfox.com>
 * Based on a preliminary version from Harald Welte <HaraldWelte@viatech.com>
 * Timer code by Wim Van Sebroeck <wim@iguana.be>
 *
 * Caveat: PnP must be enabled in BIOS to allow full access to watchdog
 * control registers. If not, the watchdog must be configured in BIOS manually.
 */


#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <linux/device.h>
#include <linux/io.h>
#include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/timer.h>
#include <linux/watchdog.h>

/* Configuration registers relative to the pci device */

#define VIA_WDT_MMIO_BASE	0xe8	
/* MMIO region base address */

#define VIA_WDT_CONF		0xec	
/* watchdog enable state */

/* Relevant bits for the VIA_WDT_CONF register */

#define VIA_WDT_CONF_ENABLE	0x01	
/* 1: enable watchdog */

#define VIA_WDT_CONF_MMIO	0x02	
/* 1: enable watchdog MMIO */

/*
 * The MMIO region contains the watchog control register and the
 * hardware timer counter.
 */

#define VIA_WDT_MMIO_LEN	8	
/* MMIO region length in bytes */

#define VIA_WDT_CTL		0	
/* MMIO addr+0: state/control reg. */

#define VIA_WDT_COUNT		4	
/* MMIO addr+4: timer counter reg. */

/* Bits for the VIA_WDT_CTL register */

#define VIA_WDT_RUNNING		0x01	
/* 0: stop, 1: running */

#define VIA_WDT_FIRED		0x02	
/* 1: restarted by expired watchdog */

#define VIA_WDT_PWROFF		0x04	
/* 0: reset, 1: poweroff */

#define VIA_WDT_DISABLED	0x08	
/* 1: timer is disabled */

#define VIA_WDT_TRIGGER		0x80	
/* 1: start a new countdown */

/* Hardware heartbeat in seconds */

#define WDT_HW_HEARTBEAT 1

/* Timer heartbeat (500ms) */

#define WDT_HEARTBEAT	(HZ/2)	
/* should be <= ((WDT_HW_HEARTBEAT*HZ)/2) */

/* User space timeout in seconds */

#define WDT_TIMEOUT_MAX	1023	
/* approx. 17 min. */

#define WDT_TIMEOUT	60

static int timeout = WDT_TIMEOUT;
module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds, between 1 and 1023 "
	"(default = " __MODULE_STRING(WDT_TIMEOUT) ")");


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


static struct watchdog_device wdt_dev;

static struct resource wdt_res;

static void __iomem *wdt_mem;

static unsigned int mmio;
static void wdt_timer_tick(unsigned long data);
static DEFINE_TIMER(timer, wdt_timer_tick, 0, 0);
					/* The timer that pings the watchdog */

static unsigned long next_heartbeat;	
/* the next_heartbeat for the timer */


static inline void wdt_reset(void) { unsigned int ctl = readl(wdt_mem); writel(ctl | VIA_WDT_TRIGGER, wdt_mem); }

Contributors

PersonTokensPropCommitsCommitProp
Marc Vertes27100.00%1100.00%
Total27100.00%1100.00%

/* * Timer tick: the timer will make sure that the watchdog timer hardware * is being reset in time. The conditions to do this are: * 1) the watchog timer has been started and /dev/watchdog is open * and there is still time left before userspace should send the * next heartbeat/ping. (note: the internal heartbeat is much smaller * then the external/userspace heartbeat). * 2) the watchdog timer has been stopped by userspace. */
static void wdt_timer_tick(unsigned long data) { if (time_before(jiffies, next_heartbeat) || (!watchdog_active(&wdt_dev))) { wdt_reset(); mod_timer(&timer, jiffies + WDT_HEARTBEAT); } else pr_crit("I will reboot your machine !\n"); }

Contributors

PersonTokensPropCommitsCommitProp
Marc Vertes4897.96%150.00%
Viresh Kumar12.04%150.00%
Total49100.00%2100.00%


static int wdt_ping(struct watchdog_device *wdd) { /* calculate when the next userspace timeout will be */ next_heartbeat = jiffies + wdd->timeout * HZ; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Marc Vertes2392.00%150.00%
Wim Van Sebroeck28.00%150.00%
Total25100.00%2100.00%


static int wdt_start(struct watchdog_device *wdd) { unsigned int ctl = readl(wdt_mem); writel(wdd->timeout, wdt_mem + VIA_WDT_COUNT); writel(ctl | VIA_WDT_RUNNING | VIA_WDT_TRIGGER, wdt_mem); wdt_ping(wdd); mod_timer(&timer, jiffies + WDT_HEARTBEAT); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Marc Vertes5896.67%150.00%
Wim Van Sebroeck23.33%150.00%
Total60100.00%2100.00%


static int wdt_stop(struct watchdog_device *wdd) { unsigned int ctl = readl(wdt_mem); writel(ctl & ~VIA_WDT_RUNNING, wdt_mem); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Marc Vertes33100.00%1100.00%
Total33100.00%1100.00%


static int wdt_set_timeout(struct watchdog_device *wdd, unsigned int new_timeout) { writel(new_timeout, wdt_mem + VIA_WDT_COUNT); wdd->timeout = new_timeout; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Marc Vertes3193.94%150.00%
Wim Van Sebroeck26.06%150.00%
Total33100.00%2100.00%

static const struct watchdog_info wdt_info = { .identity = "VIA watchdog", .options = WDIOF_CARDRESET | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, }; static const struct watchdog_ops wdt_ops = { .owner = THIS_MODULE, .start = wdt_start, .stop = wdt_stop, .ping = wdt_ping, .set_timeout = wdt_set_timeout, }; static struct watchdog_device wdt_dev = { .info = &wdt_info, .ops = &wdt_ops, .min_timeout = 1, .max_timeout = WDT_TIMEOUT_MAX, };
static int wdt_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { unsigned char conf; int ret = -ENODEV; if (pci_enable_device(pdev)) { dev_err(&pdev->dev, "cannot enable PCI device\n"); return -ENODEV; } /* * Allocate a MMIO region which contains watchdog control register * and counter, then configure the watchdog to use this region. * This is possible only if PnP is properly enabled in BIOS. * If not, the watchdog must be configured in BIOS manually. */ if (allocate_resource(&iomem_resource, &wdt_res, VIA_WDT_MMIO_LEN, 0xf0000000, 0xffffff00, 0xff, NULL, NULL)) { dev_err(&pdev->dev, "MMIO allocation failed\n"); goto err_out_disable_device; } pci_write_config_dword(pdev, VIA_WDT_MMIO_BASE, wdt_res.start); pci_read_config_byte(pdev, VIA_WDT_CONF, &conf); conf |= VIA_WDT_CONF_ENABLE | VIA_WDT_CONF_MMIO; pci_write_config_byte(pdev, VIA_WDT_CONF, conf); pci_read_config_dword(pdev, VIA_WDT_MMIO_BASE, &mmio); if (mmio) { dev_info(&pdev->dev, "VIA Chipset watchdog MMIO: %x\n", mmio); } else { dev_err(&pdev->dev, "MMIO setting failed. Check BIOS.\n"); goto err_out_resource; } if (!request_mem_region(mmio, VIA_WDT_MMIO_LEN, "via_wdt")) { dev_err(&pdev->dev, "MMIO region busy\n"); goto err_out_resource; } wdt_mem = ioremap(mmio, VIA_WDT_MMIO_LEN); if (wdt_mem == NULL) { dev_err(&pdev->dev, "cannot remap VIA wdt MMIO registers\n"); goto err_out_release; } if (timeout < 1 || timeout > WDT_TIMEOUT_MAX) timeout = WDT_TIMEOUT; wdt_dev.timeout = timeout; wdt_dev.parent = &pdev->dev; watchdog_set_nowayout(&wdt_dev, nowayout); if (readl(wdt_mem) & VIA_WDT_FIRED) wdt_dev.bootstatus |= WDIOF_CARDRESET; ret = watchdog_register_device(&wdt_dev); if (ret) goto err_out_iounmap; /* start triggering, in case of watchdog already enabled by BIOS */ mod_timer(&timer, jiffies + WDT_HEARTBEAT); return 0; err_out_iounmap: iounmap(wdt_mem); err_out_release: release_mem_region(mmio, VIA_WDT_MMIO_LEN); err_out_resource: release_resource(&wdt_res); err_out_disable_device: pci_disable_device(pdev); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Marc Vertes31893.26%133.33%
Wim Van Sebroeck144.11%133.33%
Pratyush Anand92.64%133.33%
Total341100.00%3100.00%


static void wdt_remove(struct pci_dev *pdev) { watchdog_unregister_device(&wdt_dev); del_timer_sync(&timer); iounmap(wdt_mem); release_mem_region(mmio, VIA_WDT_MMIO_LEN); release_resource(&wdt_res); pci_disable_device(pdev); }

Contributors

PersonTokensPropCommitsCommitProp
Marc Vertes4597.83%150.00%
Julia Lawall12.17%150.00%
Total46100.00%2100.00%

static const struct pci_device_id wdt_pci_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_CX700) }, { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX800) }, { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855) }, { 0 } }; static struct pci_driver wdt_driver = { .name = "via_wdt", .id_table = wdt_pci_table, .probe = wdt_probe, .remove = wdt_remove, }; module_pci_driver(wdt_driver); MODULE_AUTHOR("Marc Vertes"); MODULE_DESCRIPTION("Driver for watchdog timer on VIA chipset"); MODULE_LICENSE("GPL");

Overall Contributors

PersonTokensPropCommitsCommitProp
Marc Vertes94894.14%19.09%
Wim Van Sebroeck242.38%327.27%
Axel Lin111.09%218.18%
Pratyush Anand90.89%19.09%
Joe Perches70.70%19.09%
Jingoo Han60.60%19.09%
Julia Lawall10.10%19.09%
Viresh Kumar10.10%19.09%
Total1007100.00%11100.00%
Directory: drivers/watchdog
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.