diff --git a/src/acpi/Kconfig b/src/acpi/Kconfig index 83d18bf62f..417ff60abb 100644 --- a/src/acpi/Kconfig +++ b/src/acpi/Kconfig @@ -111,3 +111,11 @@ config ACPI_PPTT_MAX_CACHES help This variable sets the maximum number of distinct caches per topology level. Increasing this option also increases stack usage. + +config ACPI_WDAT_WDT + bool + default n + depends on HAVE_ACPI_TABLES + help + Selected by platforms that support and fill ACPI Watchdog Action Table + (WDAT). diff --git a/src/acpi/acpi.c b/src/acpi/acpi.c index beba5fdb3a..5e769163b7 100644 --- a/src/acpi/acpi.c +++ b/src/acpi/acpi.c @@ -1218,6 +1218,25 @@ static void acpi_create_iort(acpi_header_t *header, void *unused) header->length = current - (unsigned long)iort; } +static void acpi_create_wdat(acpi_header_t *header, void *unused) +{ + if (!CONFIG(ACPI_WDAT_WDT)) + return; + + acpi_wdat_t *wdat = (acpi_wdat_t *)header; + unsigned long current = (unsigned long)wdat + sizeof(acpi_wdat_t); + + memset((void *)wdat, 0, sizeof(acpi_wdat_t)); + + if (acpi_fill_header(header, "WDAT", WDAT, sizeof(acpi_wdat_t)) != CB_SUCCESS) + return; + + current = acpi_soc_fill_wdat(wdat, current); + + /* (Re)calculate length. */ + header->length = current - (unsigned long)wdat; +} + unsigned long acpi_create_lpi_desc_ncst(acpi_lpi_desc_ncst_t *lpi_desc, uint16_t uid) { memset(lpi_desc, 0, sizeof(acpi_lpi_desc_ncst_t)); @@ -1434,6 +1453,7 @@ unsigned long write_acpi_tables(const unsigned long start) { acpi_create_gtdt, NULL, sizeof(acpi_gtdt_t) }, { acpi_create_pptt, NULL, sizeof(acpi_pptt_t) }, { acpi_create_iort, NULL, sizeof(acpi_iort_t) }, + { acpi_create_wdat, NULL, sizeof(acpi_wdat_t) }, }; current = start; @@ -1787,6 +1807,8 @@ int get_acpi_table_revision(enum acpi_tables table) return 3; case IORT: /* IO Remapping Table E.e */ return 6; + case WDAT: + return 1; default: return -1; } diff --git a/src/include/acpi/acpi.h b/src/include/acpi/acpi.h index 01504ce7d3..d5f4008358 100644 --- a/src/include/acpi/acpi.h +++ b/src/include/acpi/acpi.h @@ -102,6 +102,7 @@ enum acpi_tables { SSDT, /* Secondary System Description Table */ TCPA, /* Trusted Computing Platform Alliance Table */ TPM2, /* Trusted Platform Module 2.0 Table */ + WDAT, /* Watchdog Action Table */ XSDT, /* Extended System Description Table */ /* Additional proprietary tables used by coreboot */ CRAT, /* Component Resource Attribute Table */ @@ -1657,6 +1658,70 @@ struct acpi_gtdt_watchdog { #define ACPI_GTDT_WATCHDOG_IRQ_POLARITY (1<<1) #define ACPI_GTDT_WATCHDOG_SECURE (1<<2) +enum acpi_wdat_actions { + ACPI_WDAT_RESET = 1, + ACPI_WDAT_GET_CURRENT_COUNTDOWN = 4, + ACPI_WDAT_GET_COUNTDOWN = 5, + ACPI_WDAT_SET_COUNTDOWN = 6, + ACPI_WDAT_GET_RUNNING_STATE = 8, + ACPI_WDAT_SET_RUNNING_STATE = 9, + ACPI_WDAT_GET_STOPPED_STATE = 10, + ACPI_WDAT_SET_STOPPED_STATE = 11, + ACPI_WDAT_GET_REBOOT = 16, + ACPI_WDAT_SET_REBOOT = 17, + ACPI_WDAT_GET_SHUTDOWN = 18, + ACPI_WDAT_SET_SHUTDOWN = 19, + ACPI_WDAT_GET_STATUS = 32, + ACPI_WDAT_SET_STATUS = 33, + ACPI_WDAT_ACTION_RESERVED = 34 /* 34 and greater are reserved */ +}; + +enum acpi_wdat_instructions { + ACPI_WDAT_READ_VALUE = 0, + ACPI_WDAT_READ_COUNTDOWN = 1, + ACPI_WDAT_WRITE_VALUE = 2, + ACPI_WDAT_WRITE_COUNTDOWN = 3, + ACPI_WDAT_INSTRUCTION_RESERVED = 4, /* 4 and greater are reserved */ + ACPI_WDAT_PRESERVE_REGISTER = 0x80 /* Except for this value */ +}; + +enum acpi_wdat_flags { + ACPI_WDAT_FLAG_DISABLED = 0, + ACPI_WDAT_FLAG_ENABLED = 1 +}; + +enum acpi_wdat_access_size { + ACPI_WDAT_ACCESS_SIZE_BYTE = 1, + ACPI_WDAT_ACCESS_SIZE_WORD = 2, + ACPI_WDAT_ACCESS_SIZE_DWORD = 3 +}; + +/* ACPI WDAT */ +typedef struct acpi_wdat_entry { + u8 action; + u8 instruction; + u16 reserved; + struct acpi_gen_regaddr register_region; + u32 value; + u32 mask; +} __packed acpi_wdat_entry_t; + +typedef struct acpi_table_wdat { + acpi_header_t header; /* Common ACPI table header */ + u32 header_length; + u16 pci_segment; + u8 pci_bus; + u8 pci_device; + u8 pci_function; + u8 reserved[3]; + u32 timer_period; + u32 max_count; + u32 min_count; + u8 flags; + u8 reserved2[3]; + u32 entries; +} __packed acpi_wdat_t; + uintptr_t get_coreboot_rsdp(void); void acpi_create_einj(acpi_einj_t *einj, uintptr_t addr, u8 actions); @@ -1819,6 +1884,35 @@ unsigned long acpi_gtdt_add_timer_block(unsigned long current, const uint64_t ad unsigned long acpi_gtdt_add_watchdog(unsigned long current, uint64_t refresh_frame, uint64_t control_frame, uint32_t gsiv, uint32_t flags); +/* + * Populate primary acpi_wdat_t struct to provide basic information about watchdog and + * associated acpi_wdat_entry_t structures, which correspond to watchdog-related + * actions such as start/stop watchdog, set timeout, ping watchdog, get remaining time, + * etc. Each acpi_wdat_entry_t entry indicates what needs to be written to a specific + * address to perform a specific action or at which address the watchdog-related + * information is stored. + * + * The acpi_wdat_entry_t structures follow the acpi_wdat_t, so the table layout is as + * follows: + * +---------------------+ + * | acpi_wdat_t { | + * | ... | + * | } | + * | acpi_wdat_entry_t { | + * | ... | + * | } | + * | acpi_wdat_entry_t { | + * | ... | + * | } | + * +---------------------+ + * + * @param wdat Pointer to populate acpi_wdat_t struct + * @param current Position in memory after the acpi_wdat_t struct which also indicates + * the position where the first acpi_wdat_entry_t must be placed. + * @return Position after last acpi_wdat_entry_t struct + */ +unsigned long acpi_soc_fill_wdat(acpi_wdat_t *wdat, unsigned long current); + /* For ACPI S3 support. */ void __noreturn acpi_resume(void *wake_vec); void mainboard_suspend_resume(void);