From 017003cbd0b75119cd1ee6ff52236f8a18182c3c Mon Sep 17 00:00:00 2001 From: Marek Maslanka Date: Thu, 7 Dec 2023 13:21:35 +0000 Subject: [PATCH] acpi: Add support for WDAT table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit lays the groundwork for implementing the ACPI WDAT (Watchdog Action Table) table specification. The WDAT is a special ACPI table introduced by Microsoft that describes the watchdog for the OS. Platforms that need to implement the WDAT table must describe the hardware watchdog management operations as described in the specification. See “Links to ACPI-Related Documents” (http://uefi.org/acpi) under the heading “Watchdog Action Table”. BUG=b:314260167 TEST=Mock the acpi_soc_fill_wdat function for a specific platform/soc and enable ACPI_WDAT_WDT in the kconfig. Check if the build passes successfully. Change-Id: Ieb82d1f69b2b7fffacfd2928bc71f8ff10498074 Signed-off-by: Marek Maslanka Reviewed-on: https://review.coreboot.org/c/coreboot/+/79380 Tested-by: build bot (Jenkins) Reviewed-by: Jakub Czapiga --- src/acpi/Kconfig | 8 ++++ src/acpi/acpi.c | 22 ++++++++++ src/include/acpi/acpi.h | 94 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+) 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);