linux-watchdog 5.18-rc1 tag

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.14 (GNU/Linux)
 
 iEYEABECAAYFAmJF7qQACgkQ+iyteGJfRsowRQCeOfozOBwouAz4tVIERCaYgril
 D6sAn34jNnuYybj4YtEIBRCHWfbG6GsQ
 =oHoS
 -----END PGP SIGNATURE-----

Merge tag 'linux-watchdog-5.18-rc1' of git://www.linux-watchdog.org/linux-watchdog

Pull watchdog updates from Wim Van Sebroeck:

 - add support for BCM4908

 - renesas_wdt: add R-Car Gen4 support

 - improve watchdog_dev function documentation

 - sp5100_tco: replace the cd6h/cd7h port I/O with MMIO accesses during
   initialization

 - several other small improvements and fixes

* tag 'linux-watchdog-5.18-rc1' of git://www.linux-watchdog.org/linux-watchdog:
  Watchdog: sp5100_tco: Enable Family 17h+ CPUs
  Watchdog: sp5100_tco: Add initialization using EFCH MMIO
  Watchdog: sp5100_tco: Refactor MMIO base address initialization
  Watchdog: sp5100_tco: Move timer initialization into function
  watchdog: ixp4xx: Implement restart
  watchdog: orion_wdt: support pretimeout on Armada-XP
  watchdog: allow building BCM7038_WDT for BCM4908
  watchdog: renesas_wdt: Add R-Car Gen4 support
  dt-bindings: watchdog: renesas-wdt: Document r8a779f0 support
  watchdog: Improve watchdog_dev function documentation
  watchdog: aspeed: add nowayout support
  watchdog: rti-wdt: Add missing pm_runtime_disable() in probe function
  watchdog: imx2_wdg: Alow ping on suspend
This commit is contained in:
Linus Torvalds 2022-03-31 14:14:03 -07:00
commit 354b8bf222
11 changed files with 409 additions and 246 deletions

View file

@ -55,6 +55,11 @@ properties:
- renesas,r8a779a0-wdt # R-Car V3U
- const: renesas,rcar-gen3-wdt # R-Car Gen3 and RZ/G2
- items:
- enum:
- renesas,r8a779f0-wdt # R-Car S4-8
- const: renesas,rcar-gen4-wdt # R-Car Gen4
reg:
maxItems: 1

View file

@ -1779,7 +1779,7 @@ config BCM7038_WDT
tristate "BCM63xx/BCM7038 Watchdog"
select WATCHDOG_CORE
depends on HAS_IOMEM
depends on ARCH_BRCMSTB || BMIPS_GENERIC || BCM63XX || COMPILE_TEST
depends on ARCH_BCM4908 || ARCH_BRCMSTB || BMIPS_GENERIC || BCM63XX || COMPILE_TEST
help
Watchdog driver for the built-in hardware in Broadcom 7038 and
later SoCs used in set-top boxes. BCM7038 was made public

View file

@ -13,6 +13,11 @@
#include <linux/platform_device.h>
#include <linux/watchdog.h>
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) ")");
struct aspeed_wdt {
struct watchdog_device wdd;
void __iomem *base;
@ -266,6 +271,8 @@ static int aspeed_wdt_probe(struct platform_device *pdev)
wdt->wdd.timeout = WDT_DEFAULT_TIMEOUT;
watchdog_init_timeout(&wdt->wdd, 0, dev);
watchdog_set_nowayout(&wdt->wdd, nowayout);
np = dev->of_node;
ofdid = of_match_node(aspeed_wdt_of_table, np);

View file

@ -66,6 +66,7 @@ struct imx2_wdt_device {
struct watchdog_device wdog;
bool ext_reset;
bool clk_is_on;
bool no_ping;
};
static bool nowayout = WATCHDOG_NOWAYOUT;
@ -312,12 +313,18 @@ static int __init imx2_wdt_probe(struct platform_device *pdev)
wdev->ext_reset = of_property_read_bool(dev->of_node,
"fsl,ext-reset-output");
/*
* The i.MX7D doesn't support low power mode, so we need to ping the watchdog
* during suspend.
*/
wdev->no_ping = !of_device_is_compatible(dev->of_node, "fsl,imx7d-wdt");
platform_set_drvdata(pdev, wdog);
watchdog_set_drvdata(wdog, wdev);
watchdog_set_nowayout(wdog, nowayout);
watchdog_set_restart_priority(wdog, 128);
watchdog_init_timeout(wdog, timeout, dev);
watchdog_stop_ping_on_suspend(wdog);
if (wdev->no_ping)
watchdog_stop_ping_on_suspend(wdog);
if (imx2_wdt_is_running(wdev)) {
imx2_wdt_set_timeout(wdog, wdog->timeout);
@ -366,9 +373,11 @@ static int __maybe_unused imx2_wdt_suspend(struct device *dev)
imx2_wdt_ping(wdog);
}
clk_disable_unprepare(wdev->clk);
if (wdev->no_ping) {
clk_disable_unprepare(wdev->clk);
wdev->clk_is_on = false;
wdev->clk_is_on = false;
}
return 0;
}
@ -380,11 +389,14 @@ static int __maybe_unused imx2_wdt_resume(struct device *dev)
struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
int ret;
ret = clk_prepare_enable(wdev->clk);
if (ret)
return ret;
if (wdev->no_ping) {
ret = clk_prepare_enable(wdev->clk);
wdev->clk_is_on = true;
if (ret)
return ret;
wdev->clk_is_on = true;
}
if (watchdog_active(wdog) && !imx2_wdt_is_running(wdev)) {
/*
@ -407,6 +419,7 @@ static SIMPLE_DEV_PM_OPS(imx2_wdt_pm_ops, imx2_wdt_suspend,
static const struct of_device_id imx2_wdt_dt_ids[] = {
{ .compatible = "fsl,imx21-wdt", },
{ .compatible = "fsl,imx7d-wdt", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, imx2_wdt_dt_ids);

View file

@ -84,10 +84,24 @@ static int ixp4xx_wdt_set_timeout(struct watchdog_device *wdd,
return 0;
}
static int ixp4xx_wdt_restart(struct watchdog_device *wdd,
unsigned long action, void *data)
{
struct ixp4xx_wdt *iwdt = to_ixp4xx_wdt(wdd);
__raw_writel(IXP4XX_WDT_KEY, iwdt->base + IXP4XX_OSWK_OFFSET);
__raw_writel(0, iwdt->base + IXP4XX_OSWT_OFFSET);
__raw_writel(IXP4XX_WDT_COUNT_ENABLE | IXP4XX_WDT_RESET_ENABLE,
iwdt->base + IXP4XX_OSWE_OFFSET);
return 0;
}
static const struct watchdog_ops ixp4xx_wdt_ops = {
.start = ixp4xx_wdt_start,
.stop = ixp4xx_wdt_stop,
.set_timeout = ixp4xx_wdt_set_timeout,
.restart = ixp4xx_wdt_restart,
.owner = THIS_MODULE,
};

View file

@ -238,8 +238,10 @@ static int armada370_start(struct watchdog_device *wdt_dev)
atomic_io_modify(dev->reg + TIMER_A370_STATUS, WDT_A370_EXPIRED, 0);
/* Enable watchdog timer */
atomic_io_modify(dev->reg + TIMER_CTRL, dev->data->wdt_enable_bit,
dev->data->wdt_enable_bit);
reg = dev->data->wdt_enable_bit;
if (dev->wdt.info->options & WDIOF_PRETIMEOUT)
reg |= TIMER1_ENABLE_BIT;
atomic_io_modify(dev->reg + TIMER_CTRL, reg, reg);
/* Enable reset on watchdog */
reg = readl(dev->rstout);
@ -312,7 +314,7 @@ static int armada375_stop(struct watchdog_device *wdt_dev)
static int armada370_stop(struct watchdog_device *wdt_dev)
{
struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
u32 reg;
u32 reg, mask;
/* Disable reset on watchdog */
reg = readl(dev->rstout);
@ -320,7 +322,10 @@ static int armada370_stop(struct watchdog_device *wdt_dev)
writel(reg, dev->rstout);
/* Disable watchdog timer */
atomic_io_modify(dev->reg + TIMER_CTRL, dev->data->wdt_enable_bit, 0);
mask = dev->data->wdt_enable_bit;
if (wdt_dev->info->options & WDIOF_PRETIMEOUT)
mask |= TIMER1_ENABLE_BIT;
atomic_io_modify(dev->reg + TIMER_CTRL, mask, 0);
return 0;
}

View file

@ -327,6 +327,7 @@ static SIMPLE_DEV_PM_OPS(rwdt_pm_ops, rwdt_suspend, rwdt_resume);
static const struct of_device_id rwdt_ids[] = {
{ .compatible = "renesas,rcar-gen2-wdt", },
{ .compatible = "renesas,rcar-gen3-wdt", },
{ .compatible = "renesas,rcar-gen4-wdt", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, rwdt_ids);

View file

@ -228,6 +228,7 @@ static int rti_wdt_probe(struct platform_device *pdev)
ret = pm_runtime_get_sync(dev);
if (ret) {
pm_runtime_put_noidle(dev);
pm_runtime_disable(&pdev->dev);
return dev_err_probe(dev, ret, "runtime pm failed\n");
}

View file

@ -49,7 +49,7 @@
/* internal variables */
enum tco_reg_layout {
sp5100, sb800, efch
sp5100, sb800, efch, efch_mmio
};
struct sp5100_tco {
@ -86,6 +86,10 @@ static enum tco_reg_layout tco_reg_layout(struct pci_dev *dev)
dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS &&
dev->revision < 0x40) {
return sp5100;
} else if (dev->vendor == PCI_VENDOR_ID_AMD &&
sp5100_tco_pci->device == PCI_DEVICE_ID_AMD_KERNCZ_SMBUS &&
sp5100_tco_pci->revision >= AMD_ZEN_SMBUS_PCI_REV) {
return efch_mmio;
} else if (dev->vendor == PCI_VENDOR_ID_AMD &&
((dev->device == PCI_DEVICE_ID_AMD_HUDSON2_SMBUS &&
dev->revision >= 0x41) ||
@ -209,6 +213,8 @@ static void tco_timer_enable(struct sp5100_tco *tco)
~EFCH_PM_WATCHDOG_DISABLE,
EFCH_PM_DECODEEN_SECOND_RES);
break;
default:
break;
}
}
@ -223,14 +229,195 @@ static u32 sp5100_tco_read_pm_reg32(u8 index)
return val;
}
static u32 sp5100_tco_request_region(struct device *dev,
u32 mmio_addr,
const char *dev_name)
{
if (!devm_request_mem_region(dev, mmio_addr, SP5100_WDT_MEM_MAP_SIZE,
dev_name)) {
dev_dbg(dev, "MMIO address 0x%08x already in use\n", mmio_addr);
return 0;
}
return mmio_addr;
}
static u32 sp5100_tco_prepare_base(struct sp5100_tco *tco,
u32 mmio_addr,
u32 alt_mmio_addr,
const char *dev_name)
{
struct device *dev = tco->wdd.parent;
dev_dbg(dev, "Got 0x%08x from SBResource_MMIO register\n", mmio_addr);
if (!mmio_addr && !alt_mmio_addr)
return -ENODEV;
/* Check for MMIO address and alternate MMIO address conflicts */
if (mmio_addr)
mmio_addr = sp5100_tco_request_region(dev, mmio_addr, dev_name);
if (!mmio_addr && alt_mmio_addr)
mmio_addr = sp5100_tco_request_region(dev, alt_mmio_addr, dev_name);
if (!mmio_addr) {
dev_err(dev, "Failed to reserve MMIO or alternate MMIO region\n");
return -EBUSY;
}
tco->tcobase = devm_ioremap(dev, mmio_addr, SP5100_WDT_MEM_MAP_SIZE);
if (!tco->tcobase) {
dev_err(dev, "MMIO address 0x%08x failed mapping\n", mmio_addr);
devm_release_mem_region(dev, mmio_addr, SP5100_WDT_MEM_MAP_SIZE);
return -ENOMEM;
}
dev_info(dev, "Using 0x%08x for watchdog MMIO address\n", mmio_addr);
return 0;
}
static int sp5100_tco_timer_init(struct sp5100_tco *tco)
{
struct watchdog_device *wdd = &tco->wdd;
struct device *dev = wdd->parent;
u32 val;
val = readl(SP5100_WDT_CONTROL(tco->tcobase));
if (val & SP5100_WDT_DISABLED) {
dev_err(dev, "Watchdog hardware is disabled\n");
return -ENODEV;
}
/*
* Save WatchDogFired status, because WatchDogFired flag is
* cleared here.
*/
if (val & SP5100_WDT_FIRED)
wdd->bootstatus = WDIOF_CARDRESET;
/* Set watchdog action to reset the system */
val &= ~SP5100_WDT_ACTION_RESET;
writel(val, SP5100_WDT_CONTROL(tco->tcobase));
/* Set a reasonable heartbeat before we stop the timer */
tco_timer_set_timeout(wdd, wdd->timeout);
/*
* Stop the TCO before we change anything so we don't race with
* a zeroed timer.
*/
tco_timer_stop(wdd);
return 0;
}
static u8 efch_read_pm_reg8(void __iomem *addr, u8 index)
{
return readb(addr + index);
}
static void efch_update_pm_reg8(void __iomem *addr, u8 index, u8 reset, u8 set)
{
u8 val;
val = readb(addr + index);
val &= reset;
val |= set;
writeb(val, addr + index);
}
static void tco_timer_enable_mmio(void __iomem *addr)
{
efch_update_pm_reg8(addr, EFCH_PM_DECODEEN3,
~EFCH_PM_WATCHDOG_DISABLE,
EFCH_PM_DECODEEN_SECOND_RES);
}
static int sp5100_tco_setupdevice_mmio(struct device *dev,
struct watchdog_device *wdd)
{
struct sp5100_tco *tco = watchdog_get_drvdata(wdd);
const char *dev_name = SB800_DEVNAME;
u32 mmio_addr = 0, alt_mmio_addr = 0;
struct resource *res;
void __iomem *addr;
int ret;
u32 val;
res = request_mem_region_muxed(EFCH_PM_ACPI_MMIO_PM_ADDR,
EFCH_PM_ACPI_MMIO_PM_SIZE,
"sp5100_tco");
if (!res) {
dev_err(dev,
"Memory region 0x%08x already in use\n",
EFCH_PM_ACPI_MMIO_PM_ADDR);
return -EBUSY;
}
addr = ioremap(EFCH_PM_ACPI_MMIO_PM_ADDR, EFCH_PM_ACPI_MMIO_PM_SIZE);
if (!addr) {
dev_err(dev, "Address mapping failed\n");
ret = -ENOMEM;
goto out;
}
/*
* EFCH_PM_DECODEEN_WDT_TMREN is dual purpose. This bitfield
* enables sp5100_tco register MMIO space decoding. The bitfield
* also starts the timer operation. Enable if not already enabled.
*/
val = efch_read_pm_reg8(addr, EFCH_PM_DECODEEN);
if (!(val & EFCH_PM_DECODEEN_WDT_TMREN)) {
efch_update_pm_reg8(addr, EFCH_PM_DECODEEN, 0xff,
EFCH_PM_DECODEEN_WDT_TMREN);
}
/* Error if the timer could not be enabled */
val = efch_read_pm_reg8(addr, EFCH_PM_DECODEEN);
if (!(val & EFCH_PM_DECODEEN_WDT_TMREN)) {
dev_err(dev, "Failed to enable the timer\n");
ret = -EFAULT;
goto out;
}
mmio_addr = EFCH_PM_WDT_ADDR;
/* Determine alternate MMIO base address */
val = efch_read_pm_reg8(addr, EFCH_PM_ISACONTROL);
if (val & EFCH_PM_ISACONTROL_MMIOEN)
alt_mmio_addr = EFCH_PM_ACPI_MMIO_ADDR +
EFCH_PM_ACPI_MMIO_WDT_OFFSET;
ret = sp5100_tco_prepare_base(tco, mmio_addr, alt_mmio_addr, dev_name);
if (!ret) {
tco_timer_enable_mmio(addr);
ret = sp5100_tco_timer_init(tco);
}
out:
if (addr)
iounmap(addr);
release_resource(res);
return ret;
}
static int sp5100_tco_setupdevice(struct device *dev,
struct watchdog_device *wdd)
{
struct sp5100_tco *tco = watchdog_get_drvdata(wdd);
const char *dev_name;
u32 mmio_addr = 0, val;
u32 alt_mmio_addr = 0;
int ret;
if (tco->tco_reg_layout == efch_mmio)
return sp5100_tco_setupdevice_mmio(dev, wdd);
/* Request the IO ports used by this driver */
if (!request_muxed_region(SP5100_IO_PM_INDEX_REG,
SP5100_PM_IOPORTS_SIZE, "sp5100_tco")) {
@ -247,138 +434,55 @@ static int sp5100_tco_setupdevice(struct device *dev,
dev_name = SP5100_DEVNAME;
mmio_addr = sp5100_tco_read_pm_reg32(SP5100_PM_WATCHDOG_BASE) &
0xfffffff8;
/*
* Secondly, find the watchdog timer MMIO address
* from SBResource_MMIO register.
*/
/* Read SBResource_MMIO from PCI config(PCI_Reg: 9Ch) */
pci_read_config_dword(sp5100_tco_pci,
SP5100_SB_RESOURCE_MMIO_BASE,
&val);
/* Verify MMIO is enabled and using bar0 */
if ((val & SB800_ACPI_MMIO_MASK) == SB800_ACPI_MMIO_DECODE_EN)
alt_mmio_addr = (val & ~0xfff) + SB800_PM_WDT_MMIO_OFFSET;
break;
case sb800:
dev_name = SB800_DEVNAME;
mmio_addr = sp5100_tco_read_pm_reg32(SB800_PM_WATCHDOG_BASE) &
0xfffffff8;
/* Read SBResource_MMIO from AcpiMmioEn(PM_Reg: 24h) */
val = sp5100_tco_read_pm_reg32(SB800_PM_ACPI_MMIO_EN);
/* Verify MMIO is enabled and using bar0 */
if ((val & SB800_ACPI_MMIO_MASK) == SB800_ACPI_MMIO_DECODE_EN)
alt_mmio_addr = (val & ~0xfff) + SB800_PM_WDT_MMIO_OFFSET;
break;
case efch:
dev_name = SB800_DEVNAME;
/*
* On Family 17h devices, the EFCH_PM_DECODEEN_WDT_TMREN bit of
* EFCH_PM_DECODEEN not only enables the EFCH_PM_WDT_ADDR memory
* region, it also enables the watchdog itself.
*/
if (boot_cpu_data.x86 == 0x17) {
val = sp5100_tco_read_pm_reg8(EFCH_PM_DECODEEN);
if (!(val & EFCH_PM_DECODEEN_WDT_TMREN)) {
sp5100_tco_update_pm_reg8(EFCH_PM_DECODEEN, 0xff,
EFCH_PM_DECODEEN_WDT_TMREN);
}
}
val = sp5100_tco_read_pm_reg8(EFCH_PM_DECODEEN);
if (val & EFCH_PM_DECODEEN_WDT_TMREN)
mmio_addr = EFCH_PM_WDT_ADDR;
val = sp5100_tco_read_pm_reg8(EFCH_PM_ISACONTROL);
if (val & EFCH_PM_ISACONTROL_MMIOEN)
alt_mmio_addr = EFCH_PM_ACPI_MMIO_ADDR +
EFCH_PM_ACPI_MMIO_WDT_OFFSET;
break;
default:
return -ENODEV;
}
/* Check MMIO address conflict */
if (!mmio_addr ||
!devm_request_mem_region(dev, mmio_addr, SP5100_WDT_MEM_MAP_SIZE,
dev_name)) {
if (mmio_addr)
dev_dbg(dev, "MMIO address 0x%08x already in use\n",
mmio_addr);
switch (tco->tco_reg_layout) {
case sp5100:
/*
* Secondly, Find the watchdog timer MMIO address
* from SBResource_MMIO register.
*/
/* Read SBResource_MMIO from PCI config(PCI_Reg: 9Ch) */
pci_read_config_dword(sp5100_tco_pci,
SP5100_SB_RESOURCE_MMIO_BASE,
&mmio_addr);
if ((mmio_addr & (SB800_ACPI_MMIO_DECODE_EN |
SB800_ACPI_MMIO_SEL)) !=
SB800_ACPI_MMIO_DECODE_EN) {
ret = -ENODEV;
goto unreg_region;
}
mmio_addr &= ~0xFFF;
mmio_addr += SB800_PM_WDT_MMIO_OFFSET;
break;
case sb800:
/* Read SBResource_MMIO from AcpiMmioEn(PM_Reg: 24h) */
mmio_addr =
sp5100_tco_read_pm_reg32(SB800_PM_ACPI_MMIO_EN);
if ((mmio_addr & (SB800_ACPI_MMIO_DECODE_EN |
SB800_ACPI_MMIO_SEL)) !=
SB800_ACPI_MMIO_DECODE_EN) {
ret = -ENODEV;
goto unreg_region;
}
mmio_addr &= ~0xFFF;
mmio_addr += SB800_PM_WDT_MMIO_OFFSET;
break;
case efch:
val = sp5100_tco_read_pm_reg8(EFCH_PM_ISACONTROL);
if (!(val & EFCH_PM_ISACONTROL_MMIOEN)) {
ret = -ENODEV;
goto unreg_region;
}
mmio_addr = EFCH_PM_ACPI_MMIO_ADDR +
EFCH_PM_ACPI_MMIO_WDT_OFFSET;
break;
}
dev_dbg(dev, "Got 0x%08x from SBResource_MMIO register\n",
mmio_addr);
if (!devm_request_mem_region(dev, mmio_addr,
SP5100_WDT_MEM_MAP_SIZE,
dev_name)) {
dev_dbg(dev, "MMIO address 0x%08x already in use\n",
mmio_addr);
ret = -EBUSY;
goto unreg_region;
}
ret = sp5100_tco_prepare_base(tco, mmio_addr, alt_mmio_addr, dev_name);
if (!ret) {
/* Setup the watchdog timer */
tco_timer_enable(tco);
ret = sp5100_tco_timer_init(tco);
}
tco->tcobase = devm_ioremap(dev, mmio_addr, SP5100_WDT_MEM_MAP_SIZE);
if (!tco->tcobase) {
dev_err(dev, "failed to get tcobase address\n");
ret = -ENOMEM;
goto unreg_region;
}
dev_info(dev, "Using 0x%08x for watchdog MMIO address\n", mmio_addr);
/* Setup the watchdog timer */
tco_timer_enable(tco);
val = readl(SP5100_WDT_CONTROL(tco->tcobase));
if (val & SP5100_WDT_DISABLED) {
dev_err(dev, "Watchdog hardware is disabled\n");
ret = -ENODEV;
goto unreg_region;
}
/*
* Save WatchDogFired status, because WatchDogFired flag is
* cleared here.
*/
if (val & SP5100_WDT_FIRED)
wdd->bootstatus = WDIOF_CARDRESET;
/* Set watchdog action to reset the system */
val &= ~SP5100_WDT_ACTION_RESET;
writel(val, SP5100_WDT_CONTROL(tco->tcobase));
/* Set a reasonable heartbeat before we stop the timer */
tco_timer_set_timeout(wdd, wdd->timeout);
/*
* Stop the TCO before we change anything so we don't race with
* a zeroed timer.
*/
tco_timer_stop(wdd);
release_region(SP5100_IO_PM_INDEX_REG, SP5100_PM_IOPORTS_SIZE);
return 0;
unreg_region:
release_region(SP5100_IO_PM_INDEX_REG, SP5100_PM_IOPORTS_SIZE);
return ret;
}

View file

@ -58,6 +58,7 @@
#define SB800_PM_WATCHDOG_SECOND_RES GENMASK(1, 0)
#define SB800_ACPI_MMIO_DECODE_EN BIT(0)
#define SB800_ACPI_MMIO_SEL BIT(1)
#define SB800_ACPI_MMIO_MASK GENMASK(1, 0)
#define SB800_PM_WDT_MMIO_OFFSET 0xB00
@ -82,4 +83,10 @@
#define EFCH_PM_ISACONTROL_MMIOEN BIT(1)
#define EFCH_PM_ACPI_MMIO_ADDR 0xfed80000
#define EFCH_PM_ACPI_MMIO_PM_OFFSET 0x00000300
#define EFCH_PM_ACPI_MMIO_WDT_OFFSET 0x00000b00
#define EFCH_PM_ACPI_MMIO_PM_ADDR (EFCH_PM_ACPI_MMIO_ADDR + \
EFCH_PM_ACPI_MMIO_PM_OFFSET)
#define EFCH_PM_ACPI_MMIO_PM_SIZE 8
#define AMD_ZEN_SMBUS_PCI_REV 0x51

View file

@ -171,17 +171,17 @@ static int __watchdog_ping(struct watchdog_device *wdd)
}
/*
* watchdog_ping: ping the watchdog.
* @wdd: the watchdog device to ping
* watchdog_ping - ping the watchdog
* @wdd: The watchdog device to ping
*
* The caller must hold wd_data->lock.
* If the watchdog has no own ping operation then it needs to be
* restarted via the start operation. This wrapper function does
* exactly that.
* We only ping when the watchdog device is running.
* The caller must hold wd_data->lock.
*
* If the watchdog has no own ping operation then it needs to be
* restarted via the start operation. This wrapper function does
* exactly that.
* We only ping when the watchdog device is running.
* Return: 0 on success, error otherwise.
*/
static int watchdog_ping(struct watchdog_device *wdd)
{
struct watchdog_core_data *wd_data = wdd->wd_data;
@ -231,16 +231,14 @@ static enum hrtimer_restart watchdog_timer_expired(struct hrtimer *timer)
}
/*
* watchdog_start: wrapper to start the watchdog.
* @wdd: the watchdog device to start
* watchdog_start - wrapper to start the watchdog
* @wdd: The watchdog device to start
*
* The caller must hold wd_data->lock.
* Start the watchdog if it is not active and mark it active.
* The caller must hold wd_data->lock.
*
* Start the watchdog if it is not active and mark it active.
* This function returns zero on success or a negative errno code for
* failure.
* Return: 0 on success or a negative errno code for failure.
*/
static int watchdog_start(struct watchdog_device *wdd)
{
struct watchdog_core_data *wd_data = wdd->wd_data;
@ -274,17 +272,15 @@ static int watchdog_start(struct watchdog_device *wdd)
}
/*
* watchdog_stop: wrapper to stop the watchdog.
* @wdd: the watchdog device to stop
* watchdog_stop - wrapper to stop the watchdog
* @wdd: The watchdog device to stop
*
* The caller must hold wd_data->lock.
* Stop the watchdog if it is still active and unmark it active.
* If the 'nowayout' feature was set, the watchdog cannot be stopped.
* The caller must hold wd_data->lock.
*
* Stop the watchdog if it is still active and unmark it active.
* This function returns zero on success or a negative errno code for
* failure.
* If the 'nowayout' feature was set, the watchdog cannot be stopped.
* Return: 0 on success or a negative errno code for failure.
*/
static int watchdog_stop(struct watchdog_device *wdd)
{
int err = 0;
@ -315,14 +311,14 @@ static int watchdog_stop(struct watchdog_device *wdd)
}
/*
* watchdog_get_status: wrapper to get the watchdog status
* @wdd: the watchdog device to get the status from
* watchdog_get_status - wrapper to get the watchdog status
* @wdd: The watchdog device to get the status from
*
* The caller must hold wd_data->lock.
* Get the watchdog's status flags.
* The caller must hold wd_data->lock.
*
* Get the watchdog's status flags.
* Return: watchdog's status flags.
*/
static unsigned int watchdog_get_status(struct watchdog_device *wdd)
{
struct watchdog_core_data *wd_data = wdd->wd_data;
@ -352,13 +348,14 @@ static unsigned int watchdog_get_status(struct watchdog_device *wdd)
}
/*
* watchdog_set_timeout: set the watchdog timer timeout
* @wdd: the watchdog device to set the timeout for
* @timeout: timeout to set in seconds
* watchdog_set_timeout - set the watchdog timer timeout
* @wdd: The watchdog device to set the timeout for
* @timeout: Timeout to set in seconds
*
* The caller must hold wd_data->lock.
* The caller must hold wd_data->lock.
*
* Return: 0 if successful, error otherwise.
*/
static int watchdog_set_timeout(struct watchdog_device *wdd,
unsigned int timeout)
{
@ -385,11 +382,12 @@ static int watchdog_set_timeout(struct watchdog_device *wdd,
}
/*
* watchdog_set_pretimeout: set the watchdog timer pretimeout
* @wdd: the watchdog device to set the timeout for
* @timeout: pretimeout to set in seconds
* watchdog_set_pretimeout - set the watchdog timer pretimeout
* @wdd: The watchdog device to set the timeout for
* @timeout: pretimeout to set in seconds
*
* Return: 0 if successful, error otherwise.
*/
static int watchdog_set_pretimeout(struct watchdog_device *wdd,
unsigned int timeout)
{
@ -410,15 +408,15 @@ static int watchdog_set_pretimeout(struct watchdog_device *wdd,
}
/*
* watchdog_get_timeleft: wrapper to get the time left before a reboot
* @wdd: the watchdog device to get the remaining time from
* @timeleft: the time that's left
* watchdog_get_timeleft - wrapper to get the time left before a reboot
* @wdd: The watchdog device to get the remaining time from
* @timeleft: The time that's left
*
* The caller must hold wd_data->lock.
* Get the time before a watchdog will reboot (if not pinged).
* The caller must hold wd_data->lock.
*
* Get the time before a watchdog will reboot (if not pinged).
* Return: 0 if successful, error otherwise.
*/
static int watchdog_get_timeleft(struct watchdog_device *wdd,
unsigned int *timeleft)
{
@ -635,14 +633,15 @@ __ATTRIBUTE_GROUPS(wdt);
#endif
/*
* watchdog_ioctl_op: call the watchdog drivers ioctl op if defined
* @wdd: the watchdog device to do the ioctl on
* @cmd: watchdog command
* @arg: argument pointer
* watchdog_ioctl_op - call the watchdog drivers ioctl op if defined
* @wdd: The watchdog device to do the ioctl on
* @cmd: Watchdog command
* @arg: Argument pointer
*
* The caller must hold wd_data->lock.
* The caller must hold wd_data->lock.
*
* Return: 0 if successful, error otherwise.
*/
static int watchdog_ioctl_op(struct watchdog_device *wdd, unsigned int cmd,
unsigned long arg)
{
@ -653,17 +652,18 @@ static int watchdog_ioctl_op(struct watchdog_device *wdd, unsigned int cmd,
}
/*
* watchdog_write: writes to the watchdog.
* @file: file from VFS
* @data: user address of data
* @len: length of data
* @ppos: pointer to the file offset
* watchdog_write - writes to the watchdog
* @file: File from VFS
* @data: User address of data
* @len: Length of data
* @ppos: Pointer to the file offset
*
* A write to a watchdog device is defined as a keepalive ping.
* Writing the magic 'V' sequence allows the next close to turn
* off the watchdog (if 'nowayout' is not set).
* A write to a watchdog device is defined as a keepalive ping.
* Writing the magic 'V' sequence allows the next close to turn
* off the watchdog (if 'nowayout' is not set).
*
* Return: @len if successful, error otherwise.
*/
static ssize_t watchdog_write(struct file *file, const char __user *data,
size_t len, loff_t *ppos)
{
@ -706,13 +706,15 @@ static ssize_t watchdog_write(struct file *file, const char __user *data,
}
/*
* watchdog_ioctl: handle the different ioctl's for the watchdog device.
* @file: file handle to the device
* @cmd: watchdog command
* @arg: argument pointer
* watchdog_ioctl - handle the different ioctl's for the watchdog device
* @file: File handle to the device
* @cmd: Watchdog command
* @arg: Argument pointer
*
* The watchdog API defines a common set of functions for all watchdogs
* according to their available features.
* The watchdog API defines a common set of functions for all watchdogs
* according to their available features.
*
* Return: 0 if successful, error otherwise.
*/
static long watchdog_ioctl(struct file *file, unsigned int cmd,
@ -819,15 +821,16 @@ out_ioctl:
}
/*
* watchdog_open: open the /dev/watchdog* devices.
* @inode: inode of device
* @file: file handle to device
* watchdog_open - open the /dev/watchdog* devices
* @inode: Inode of device
* @file: File handle to device
*
* When the /dev/watchdog* device gets opened, we start the watchdog.
* Watch out: the /dev/watchdog device is single open, so we make sure
* it can only be opened once.
* When the /dev/watchdog* device gets opened, we start the watchdog.
* Watch out: the /dev/watchdog device is single open, so we make sure
* it can only be opened once.
*
* Return: 0 if successful, error otherwise.
*/
static int watchdog_open(struct inode *inode, struct file *file)
{
struct watchdog_core_data *wd_data;
@ -896,15 +899,16 @@ static void watchdog_core_data_release(struct device *dev)
}
/*
* watchdog_release: release the watchdog device.
* @inode: inode of device
* @file: file handle to device
* watchdog_release - release the watchdog device
* @inode: Inode of device
* @file: File handle to device
*
* This is the code for when /dev/watchdog gets closed. We will only
* stop the watchdog when we have received the magic char (and nowayout
* was not set), else the watchdog will keep running.
* This is the code for when /dev/watchdog gets closed. We will only
* stop the watchdog when we have received the magic char (and nowayout
* was not set), else the watchdog will keep running.
*
* Always returns 0.
*/
static int watchdog_release(struct inode *inode, struct file *file)
{
struct watchdog_core_data *wd_data = file->private_data;
@ -977,14 +981,15 @@ static struct class watchdog_class = {
};
/*
* watchdog_cdev_register: register watchdog character device
* @wdd: watchdog device
* watchdog_cdev_register - register watchdog character device
* @wdd: Watchdog device
*
* Register a watchdog character device including handling the legacy
* /dev/watchdog node. /dev/watchdog is actually a miscdevice and
* thus we set it up like that.
* Register a watchdog character device including handling the legacy
* /dev/watchdog node. /dev/watchdog is actually a miscdevice and
* thus we set it up like that.
*
* Return: 0 if successful, error otherwise.
*/
static int watchdog_cdev_register(struct watchdog_device *wdd)
{
struct watchdog_core_data *wd_data;
@ -1074,13 +1079,12 @@ static int watchdog_cdev_register(struct watchdog_device *wdd)
}
/*
* watchdog_cdev_unregister: unregister watchdog character device
* @watchdog: watchdog device
* watchdog_cdev_unregister - unregister watchdog character device
* @wdd: Watchdog device
*
* Unregister watchdog character device and if needed the legacy
* /dev/watchdog device.
* Unregister watchdog character device and if needed the legacy
* /dev/watchdog device.
*/
static void watchdog_cdev_unregister(struct watchdog_device *wdd)
{
struct watchdog_core_data *wd_data = wdd->wd_data;
@ -1109,15 +1113,16 @@ static void watchdog_cdev_unregister(struct watchdog_device *wdd)
put_device(&wd_data->dev);
}
/*
* watchdog_dev_register: register a watchdog device
* @wdd: watchdog device
/**
* watchdog_dev_register - register a watchdog device
* @wdd: Watchdog device
*
* Register a watchdog device including handling the legacy
* /dev/watchdog node. /dev/watchdog is actually a miscdevice and
* thus we set it up like that.
* Register a watchdog device including handling the legacy
* /dev/watchdog node. /dev/watchdog is actually a miscdevice and
* thus we set it up like that.
*
* Return: 0 if successful, error otherwise.
*/
int watchdog_dev_register(struct watchdog_device *wdd)
{
int ret;
@ -1133,30 +1138,31 @@ int watchdog_dev_register(struct watchdog_device *wdd)
return ret;
}
/*
* watchdog_dev_unregister: unregister a watchdog device
* @watchdog: watchdog device
/**
* watchdog_dev_unregister - unregister a watchdog device
* @wdd: watchdog device
*
* Unregister watchdog device and if needed the legacy
* /dev/watchdog device.
* Unregister watchdog device and if needed the legacy
* /dev/watchdog device.
*/
void watchdog_dev_unregister(struct watchdog_device *wdd)
{
watchdog_unregister_pretimeout(wdd);
watchdog_cdev_unregister(wdd);
}
/*
* watchdog_set_last_hw_keepalive: set last HW keepalive time for watchdog
* @wdd: watchdog device
* @last_ping_ms: time since last HW heartbeat
/**
* watchdog_set_last_hw_keepalive - set last HW keepalive time for watchdog
* @wdd: Watchdog device
* @last_ping_ms: Time since last HW heartbeat
*
* Adjusts the last known HW keepalive time for a watchdog timer.
* This is needed if the watchdog is already running when the probe
* function is called, and it can't be pinged immediately. This
* function must be called immediately after watchdog registration,
* and min_hw_heartbeat_ms must be set for this to be useful.
* Adjusts the last known HW keepalive time for a watchdog timer.
* This is needed if the watchdog is already running when the probe
* function is called, and it can't be pinged immediately. This
* function must be called immediately after watchdog registration,
* and min_hw_heartbeat_ms must be set for this to be useful.
*
* Return: 0 if successful, error otherwise.
*/
int watchdog_set_last_hw_keepalive(struct watchdog_device *wdd,
unsigned int last_ping_ms)
@ -1180,12 +1186,13 @@ int watchdog_set_last_hw_keepalive(struct watchdog_device *wdd,
}
EXPORT_SYMBOL_GPL(watchdog_set_last_hw_keepalive);
/*
* watchdog_dev_init: init dev part of watchdog core
/**
* watchdog_dev_init - init dev part of watchdog core
*
* Allocate a range of chardev nodes to use for watchdog devices
* Allocate a range of chardev nodes to use for watchdog devices.
*
* Return: 0 if successful, error otherwise.
*/
int __init watchdog_dev_init(void)
{
int err;
@ -1218,12 +1225,11 @@ err_register:
return err;
}
/*
* watchdog_dev_exit: exit dev part of watchdog core
/**
* watchdog_dev_exit - exit dev part of watchdog core
*
* Release the range of chardev nodes used for watchdog devices
* Release the range of chardev nodes used for watchdog devices.
*/
void __exit watchdog_dev_exit(void)
{
unregister_chrdev_region(watchdog_devt, MAX_DOGS);