drivers/watchdog/sbsa_gwdt.c
Source file repositories/reference/linux-study-clean/drivers/watchdog/sbsa_gwdt.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/watchdog/sbsa_gwdt.c- Extension
.c- Size
- 13493 bytes
- Lines
- 458
- Domain
- Driver Families
- Bucket
- drivers/watchdog
- Inferred role
- Driver Families: implementation source
- Status
- source implementation candidate
Why This File Exists
Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.
- Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.
- Touches IRQ or DMA behavior; this matters for the representative real-device path.
- Allocates kernel memory; connect allocation flags and lifetime to context constraints.
- Defines or uses C structs; map object ownership, embedded links, reference counts, and lock ownership.
Dependency Surface
linux/io.hlinux/io-64-nonatomic-lo-hi.hlinux/interrupt.hlinux/mod_devicetable.hlinux/module.hlinux/moduleparam.hlinux/platform_device.hlinux/uaccess.hlinux/watchdog.hasm/arch_timer.h
Detected Declarations
struct sbsa_gwdtfunction sbsa_gwdt_reg_readfunction sbsa_gwdt_reg_writefunction sbsa_gwdt_set_timeoutfunction sbsa_gwdt_get_timeleftfunction sbsa_gwdt_keepalivefunction sbsa_gwdt_get_versionfunction sbsa_gwdt_startfunction sbsa_gwdt_stopfunction sbsa_gwdt_interruptfunction sbsa_gwdt_probefunction sbsa_gwdt_suspendfunction sbsa_gwdt_resume
Annotated Snippet
struct sbsa_gwdt {
struct watchdog_device wdd;
u32 clk;
int version;
bool need_ws0_race_workaround;
void __iomem *refresh_base;
void __iomem *control_base;
};
#define DEFAULT_TIMEOUT 10 /* seconds */
static unsigned int timeout;
module_param(timeout, uint, 0);
MODULE_PARM_DESC(timeout,
"Watchdog timeout in seconds. (>=0, default="
__MODULE_STRING(DEFAULT_TIMEOUT) ")");
/*
* action refers to action taken when watchdog gets WS0
* 0 = skip
* 1 = panic
* defaults to skip (0)
*/
static int action;
module_param(action, int, 0);
MODULE_PARM_DESC(action, "after watchdog gets WS0 interrupt, do: "
"0 = skip(*) 1 = panic");
static bool nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, bool, S_IRUGO);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
/*
* Arm Base System Architecture 1.0 introduces watchdog v1 which
* increases the length watchdog offset register to 48 bits.
* - For version 0: WOR is 32 bits;
* - For version 1: WOR is 48 bits which comprises the register
* offset 0x8 and 0xC, and the bits [63:48] are reserved which are
* Read-As-Zero and Writes-Ignored.
*/
static u64 sbsa_gwdt_reg_read(struct sbsa_gwdt *gwdt)
{
if (gwdt->version == 0)
return readl(gwdt->control_base + SBSA_GWDT_WOR);
else
return lo_hi_readq(gwdt->control_base + SBSA_GWDT_WOR);
}
static void sbsa_gwdt_reg_write(u64 val, struct sbsa_gwdt *gwdt)
{
if (gwdt->version == 0)
writel((u32)val, gwdt->control_base + SBSA_GWDT_WOR);
else
lo_hi_writeq(val, gwdt->control_base + SBSA_GWDT_WOR);
}
/*
* watchdog operation functions
*/
static int sbsa_gwdt_set_timeout(struct watchdog_device *wdd,
unsigned int timeout)
{
struct sbsa_gwdt *gwdt = watchdog_get_drvdata(wdd);
wdd->timeout = timeout;
timeout = clamp_t(unsigned int, timeout, 1, wdd->max_hw_heartbeat_ms / 1000);
if (action)
sbsa_gwdt_reg_write((u64)gwdt->clk * timeout, gwdt);
else
/*
* In the single stage mode, The first signal (WS0) is ignored,
* the timeout is (WOR * 2), so the WOR should be configured
* to half value of timeout.
*/
sbsa_gwdt_reg_write(((u64)gwdt->clk / 2) * timeout, gwdt);
/*
* Some watchdog hardware has a race condition where it will ignore
* sbsa_gwdt_keepalive() if it is called at the exact moment that a
* timeout occurs and WS0 is being asserted. Unfortunately, the default
* behavior of the watchdog core is very likely to trigger this race
* when action=0 because it programs WOR to be half of the desired
* timeout, and watchdog_next_keepalive() chooses the exact same time to
* send keepalive pings.
*
* This triggers a race where sbsa_gwdt_keepalive() can be called right
* as WS0 is being asserted, and affected hardware will ignore that
Annotation
- Immediate include surface: `linux/io.h`, `linux/io-64-nonatomic-lo-hi.h`, `linux/interrupt.h`, `linux/mod_devicetable.h`, `linux/module.h`, `linux/moduleparam.h`, `linux/platform_device.h`, `linux/uaccess.h`.
- Detected declarations: `struct sbsa_gwdt`, `function sbsa_gwdt_reg_read`, `function sbsa_gwdt_reg_write`, `function sbsa_gwdt_set_timeout`, `function sbsa_gwdt_get_timeleft`, `function sbsa_gwdt_keepalive`, `function sbsa_gwdt_get_version`, `function sbsa_gwdt_start`, `function sbsa_gwdt_stop`, `function sbsa_gwdt_interrupt`.
- Atlas domain: Driver Families / drivers/watchdog.
- Implementation status: source implementation candidate.
- IRQ or DMA behavior appears here, which is relevant to the selected PCIe/NVMe device path.
Implementation Notes
- This generated page is the file-by-file coverage layer; curated subsystem chapters should link here when they synthesize a multi-file control flow.
- Core OS pages should be promoted from atlas-only to deep-reviewed when they explain data structures, invariants, locking, lifecycle, and C implementation snippets.
- Driver-family pages are intentionally pattern-oriented unless they are part of the selected PCIe/NVMe representative device path.