Michael Niewöhner has submitted this change. ( https://review.coreboot.org/c/coreboot/+/48090 )
Change subject: soc/intel/common/block/gpio: add code for NMI enabling ......................................................................
soc/intel/common/block/gpio: add code for NMI enabling
Especially server boards, like the Supermicro X11SSM-F, often have a NMI button and NMI functionality that can be triggered via IPMI. The purpose of this is to cause the OS to create a system crashdump from a hang system or for debugging.
Add code for enabling NMI interrupts on GPIOs configured with PAD_CFG_GPI_NMI. The enabling mechanism is the same as SMI, so the SMI function was copied and adapted. The `pad_community` struct gained two variables for the registers.
Also register the NMI for LINT1 in the MADT in accordance to ACPI spec.
Test: Linux detects the NMI correctly in dmesg: [ 0.053734] ACPI: LAPIC_NMI (acpi_id[0xff] high edge lint[0x1])
Signed-off-by: Michael Niewöhner foss@mniewoehner.de Change-Id: I4fc1a35c99c6a28b20e08a80b97bb4b8624935c9 Reviewed-on: https://review.coreboot.org/c/coreboot/+/48090 Reviewed-by: Tim Wawrzynczak twawrzynczak@chromium.org Tested-by: build bot (Jenkins) no-reply@coreboot.org --- M src/soc/intel/common/block/acpi/acpi.c M src/soc/intel/common/block/gpio/gpio.c M src/soc/intel/common/block/include/intelblocks/gpio.h M src/soc/intel/skylake/acpi.c 4 files changed, 42 insertions(+), 0 deletions(-)
Approvals: build bot (Jenkins): Verified Tim Wawrzynczak: Looks good to me, approved
diff --git a/src/soc/intel/common/block/acpi/acpi.c b/src/soc/intel/common/block/acpi/acpi.c index f0ff898..4efeb88 100644 --- a/src/soc/intel/common/block/acpi/acpi.c +++ b/src/soc/intel/common/block/acpi/acpi.c @@ -79,6 +79,9 @@ current += acpi_create_madt_irqoverride((void *)current, 0, sci, sci, flags);
+ /* NMI */ + current += acpi_create_madt_lapic_nmi((acpi_madt_lapic_nmi_t *)current, 0xff, 5, 1); + return current; }
diff --git a/src/soc/intel/common/block/gpio/gpio.c b/src/soc/intel/common/block/gpio/gpio.c index 0d21c8a..fb9287c 100644 --- a/src/soc/intel/common/block/gpio/gpio.c +++ b/src/soc/intel/common/block/gpio/gpio.c @@ -48,6 +48,10 @@ ((group) * sizeof(uint32_t))) #define GPI_SMI_EN_OFFSET(comm, group) ((comm)->gpi_smi_en_reg_0 + \ ((group) * sizeof(uint32_t))) +#define GPI_NMI_STS_OFFSET(comm, group) ((comm)->gpi_nmi_sts_reg_0 + \ + ((group) * sizeof(uint32_t))) +#define GPI_NMI_EN_OFFSET(comm, group) ((comm)->gpi_nmi_en_reg_0 + \ + ((group) * sizeof(uint32_t))) #define GPI_IS_OFFSET(comm, group) ((comm)->gpi_int_sts_reg_0 + \ ((group) * sizeof(uint32_t))) #define GPI_IE_OFFSET(comm, group) ((comm)->gpi_int_en_reg_0 + \ @@ -176,6 +180,35 @@ pcr_or32(comm->port, en_reg, en_value); }
+static void gpi_enable_nmi(const struct pad_config *cfg, + const struct pad_community *comm) +{ + uint16_t sts_reg; + uint16_t en_reg; + uint32_t en_value; + int group; + int pin; + + if (((cfg->pad_config[0]) & PAD_CFG0_ROUTE_NMI) != PAD_CFG0_ROUTE_NMI) + return; + + /* Do not configure NMI if the platform doesn't support it */ + if (!comm->gpi_nmi_sts_reg_0 || !comm->gpi_nmi_en_reg_0) + return; + + pin = relative_pad_in_comm(comm, cfg->pad); + group = gpio_group_index(comm, pin); + sts_reg = GPI_NMI_STS_OFFSET(comm, group); + en_reg = GPI_NMI_EN_OFFSET(comm, group); + en_value = gpio_bitmask_within_group(comm, pin); + + /* Write back 1 to reset the sts bit */ + pcr_rmw32(comm->port, sts_reg, en_value, 0); + + /* Set enable bits */ + pcr_or32(comm->port, en_reg, en_value); +} + static void gpio_configure_itss(const struct pad_config *cfg, uint16_t port, uint16_t pad_cfg_offset) { @@ -283,6 +316,7 @@ gpio_configure_itss(cfg, comm->port, config_offset); gpio_configure_owner(cfg, comm); gpi_enable_smi(cfg, comm); + gpi_enable_nmi(cfg, comm); }
void gpio_configure_pads(const struct pad_config *cfg, size_t num_pads) diff --git a/src/soc/intel/common/block/include/intelblocks/gpio.h b/src/soc/intel/common/block/include/intelblocks/gpio.h index 6e2bf1c..173a383 100644 --- a/src/soc/intel/common/block/include/intelblocks/gpio.h +++ b/src/soc/intel/common/block/include/intelblocks/gpio.h @@ -111,6 +111,8 @@ uint16_t gpi_int_en_reg_0; /* offset to GPI Int Enable Reg 0 */ uint16_t gpi_smi_sts_reg_0; /* offset to GPI SMI STS Reg 0 */ uint16_t gpi_smi_en_reg_0; /* offset to GPI SMI EN Reg 0 */ + uint16_t gpi_nmi_sts_reg_0; /* offset to GPI NMI STS Reg 0 */ + uint16_t gpi_nmi_en_reg_0; /* offset to GPI NMI EN Reg 0 */ uint16_t pad_cfg_base; /* offset to first PAD_GFG_DW0 Reg */ uint8_t gpi_status_offset; /* specifies offset in struct gpi_status */ diff --git a/src/soc/intel/skylake/acpi.c b/src/soc/intel/skylake/acpi.c index 98d9313..0083be5 100644 --- a/src/soc/intel/skylake/acpi.c +++ b/src/soc/intel/skylake/acpi.c @@ -522,6 +522,9 @@ irqovr = (void *)current; current += acpi_create_madt_irqoverride(irqovr, 0, sci, sci, flags);
+ /* NMI */ + current += acpi_create_madt_lapic_nmi((acpi_madt_lapic_nmi_t *)current, 0xff, 5, 1); + return current; }