mirror of
https://github.com/AsahiLinux/m1n1
synced 2024-12-22 19:43:05 +00:00
123 lines
2.3 KiB
C
123 lines
2.3 KiB
C
|
/* SPDX-License-Identifier: MIT */
|
||
|
|
||
|
#include "hv.h"
|
||
|
#include "adt.h"
|
||
|
#include "smp.h"
|
||
|
#include "uart.h"
|
||
|
#include "utils.h"
|
||
|
|
||
|
#define WDT_CPU 1
|
||
|
#define WDT_TIMEOUT 1
|
||
|
|
||
|
static bool hv_wdt_active = false;
|
||
|
static bool hv_wdt_enabled = false;
|
||
|
static volatile u64 hv_wdt_timestamp = 0;
|
||
|
static u64 hv_wdt_timeout = 0;
|
||
|
static volatile u64 hv_wdt_breadcrumbs;
|
||
|
|
||
|
static u64 cpu_dbg_base = 0;
|
||
|
|
||
|
void hv_wdt_bark(void)
|
||
|
{
|
||
|
u64 tmp = hv_wdt_breadcrumbs;
|
||
|
uart_puts("HV watchdog: bark!");
|
||
|
|
||
|
uart_printf("Breadcrumbs: ");
|
||
|
for (int i = 56; i >= 0; i -= 8) {
|
||
|
char c = (tmp >> i) & 0xff;
|
||
|
if (c)
|
||
|
uart_putchar(c);
|
||
|
}
|
||
|
uart_putchar('\n');
|
||
|
|
||
|
uart_puts("Attempting to enter proxy");
|
||
|
|
||
|
struct uartproxy_msg_start start = {
|
||
|
.reason = START_HV,
|
||
|
.code = HV_WDT_BARK,
|
||
|
};
|
||
|
|
||
|
uartproxy_run(&start);
|
||
|
reboot();
|
||
|
}
|
||
|
|
||
|
void hv_wdt_main(void)
|
||
|
{
|
||
|
while (hv_wdt_active) {
|
||
|
if (hv_wdt_enabled) {
|
||
|
sysop("dmb ish");
|
||
|
u64 timestamp = hv_wdt_timestamp;
|
||
|
sysop("isb");
|
||
|
u64 now = mrs(CNTPCT_EL0);
|
||
|
sysop("isb");
|
||
|
if ((now - timestamp) > hv_wdt_timeout)
|
||
|
hv_wdt_bark();
|
||
|
}
|
||
|
|
||
|
udelay(1000);
|
||
|
|
||
|
sysop("dmb ish");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void hv_wdt_pet(void)
|
||
|
{
|
||
|
hv_wdt_timestamp = mrs(CNTPCT_EL0);
|
||
|
sysop("dmb ish");
|
||
|
}
|
||
|
|
||
|
void hv_wdt_suspend(void)
|
||
|
{
|
||
|
hv_wdt_enabled = false;
|
||
|
sysop("dsb ish");
|
||
|
}
|
||
|
|
||
|
void hv_wdt_resume(void)
|
||
|
{
|
||
|
hv_wdt_pet();
|
||
|
hv_wdt_enabled = true;
|
||
|
sysop("dsb ish");
|
||
|
}
|
||
|
|
||
|
void hv_wdt_breadcrumb(char c)
|
||
|
{
|
||
|
u64 tmp = hv_wdt_breadcrumbs;
|
||
|
tmp <<= 8;
|
||
|
tmp |= c;
|
||
|
hv_wdt_breadcrumbs = tmp;
|
||
|
sysop("dmb ish");
|
||
|
}
|
||
|
|
||
|
void hv_wdt_init(void)
|
||
|
{
|
||
|
int node = adt_path_offset(adt, "/cpus/cpu0");
|
||
|
if (node < 0) {
|
||
|
printf("Error getting /cpus/cpu0 node\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
u64 reg[2];
|
||
|
if (ADT_GETPROP_ARRAY(adt, node, "cpu-uttdbg-reg", reg) < 0) {
|
||
|
printf("Error getting cpu-uttdbg-reg property\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
cpu_dbg_base = reg[0];
|
||
|
}
|
||
|
|
||
|
void hv_wdt_start(void)
|
||
|
{
|
||
|
hv_wdt_breadcrumbs = 0;
|
||
|
hv_wdt_timeout = mrs(CNTFRQ_EL0) * WDT_TIMEOUT;
|
||
|
hv_wdt_pet();
|
||
|
hv_wdt_active = true;
|
||
|
hv_wdt_enabled = true;
|
||
|
smp_call4(WDT_CPU, hv_wdt_main, 0, 0, 0, 0);
|
||
|
}
|
||
|
|
||
|
void hv_wdt_stop(void)
|
||
|
{
|
||
|
hv_wdt_active = false;
|
||
|
smp_wait(WDT_CPU);
|
||
|
}
|