Rizwan Qureshi (rizwan.qureshi@intel.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/16902
-gerrit
commit ac6c7b5ad718c04b510c489d5204e861778243e8 Author: Subrata Banik subrata.banik@intel.com Date: Fri Aug 19 12:33:42 2016 +0530
soc/intel/skylake: Implement Global Reset MEI message
As per ME BWG, there are two mechanism to generate a Global Reset (resets both host and Intel ME), one is through CF9h IO write of 6h or Eh with "CF9h Global Reset" (CF9GR) bit set, PMC PCI offset ACh[20]. Another is to issue the Global Reset MEI message. Because any attempts to cause global reset without synchronizing the two sides might cause unwanted side effects, such as unwritten flash data that will get destroyed if the host were to cause a global reset without informing Intel ME firmware, the recommended method is to send a Global Reset MEI message when the following conditions are met:
The PCH chipset firmware just needs to complete the Intel ME Interface #1 initialization and check the Intel ME HFSTS state if Intel ME is not in ERROR state and is accepting MEI commands then firmware should be able to use Global Reset MEI message to trigger global reset.
Furthermore, if Intel ME is in ERROR state, BIOS can use I/O 0xCF9 write of 0x06 or 0x0E command with PCH ETR3 register bit [20] to perform the global reset.
BUG=none BRANCH=none TEST=Verified Global Reset MEI message is able to perform platform global issue in ME good state.
Change-Id: If326a137eeadaa695668b76b84c510e12c546024 Signed-off-by: Subrata Banik subrata.banik@intel.com Signed-off-by: Rizwan Qureshi rizwan.qureshi@intel.com --- src/soc/intel/skylake/Makefile.inc | 3 +- src/soc/intel/skylake/include/soc/iomap.h | 2 + src/soc/intel/skylake/include/soc/me.h | 66 +++ src/soc/intel/skylake/me.c | 695 ++++++++++++++++++++++++++++++ src/soc/intel/skylake/me_status.c | 324 -------------- 5 files changed, 765 insertions(+), 325 deletions(-)
diff --git a/src/soc/intel/skylake/Makefile.inc b/src/soc/intel/skylake/Makefile.inc index ccd38ab..bf429ef 100644 --- a/src/soc/intel/skylake/Makefile.inc +++ b/src/soc/intel/skylake/Makefile.inc @@ -36,6 +36,7 @@ romstage-y += flash_controller.c romstage-y += gpio.c romstage-y += memmap.c romstage-y += monotonic_timer.c +romstage-y += me.c romstage-y += pch.c romstage-y += pcr.c romstage-y += pei_data.c @@ -59,7 +60,7 @@ ramstage-y += i2c.c ramstage-y += igd.c ramstage-y += irq.c ramstage-y += lpc.c -ramstage-y += me_status.c +ramstage-y += me.c ramstage-y += memmap.c ramstage-y += monotonic_timer.c ramstage-$(CONFIG_PLATFORM_USES_FSP1_1) += opregion.c diff --git a/src/soc/intel/skylake/include/soc/iomap.h b/src/soc/intel/skylake/include/soc/iomap.h index feba302..e736d3b 100644 --- a/src/soc/intel/skylake/include/soc/iomap.h +++ b/src/soc/intel/skylake/include/soc/iomap.h @@ -56,6 +56,8 @@
#define GPIO_BASE_SIZE 0x10000
+#define HECI1_BASE_ADDRESS 0xfed1a000 + /* * I/O port address space */ diff --git a/src/soc/intel/skylake/include/soc/me.h b/src/soc/intel/skylake/include/soc/me.h index 423e9d1..b726711 100644 --- a/src/soc/intel/skylake/include/soc/me.h +++ b/src/soc/intel/skylake/include/soc/me.h @@ -21,6 +21,10 @@ /* * Management Engine PCI registers */ +#define PCI_ME_CMDSTS 0x04 +#define ME_CMDSTS_MSE 2 +#define ME_CMDSTS_BME 4 +#define PCI_ME_BAR 0x10 #define PCI_ME_HFSTS1 0x40 #define ME_HFS_CWS_RESET 0 #define ME_HFS_CWS_INIT 1 @@ -177,6 +181,68 @@ struct me_hfs3 { u32 power_down_mitigation: 1; } __attribute__ ((packed));
+/* + * Management Engine MMIO registers + */ +#define MMIO_ME_CB_WW 0x00 +#define MMIO_HOST_CSR 0x04 + +struct host_csr { + u32 int_en: 1; + u32 int_sts: 1; + u32 int_gen: 1; + u32 host_ready: 1; + u32 host_reset: 1; + u32 rsv: 3; + u32 host_read_ptr: 8; + u32 host_write_ptr: 8; + u32 me_cir_depth: 8; +} __attribute__ ((packed)); + +#define MMIO_ME_CB_RW 0x08 +#define MMIO_ME_CSR 0x0C + +struct me_csr { + u32 int_en: 1; + u32 int_sts: 1; + u32 int_gen: 1; + u32 host_ready: 1; + u32 host_reset: 1; + u32 rsv: 3; + u32 me_read_ptr: 8; + u32 me_write_ptr: 8; + u32 me_cir_buff: 8; +} __attribute__ ((packed)); + +#define MMIO_ME_D0I3 0x800 + +/* Reset Request */ +#define MKHI_GLOBAL_RESET 0x0b + +#define GR_ORIGIN_BIOS_MEM_INIT 0x01 +#define GR_ORIGIN_BIOS_POST 0x02 +#define GR_ORIGIN_MEBX 0x03 + +#define GLOBAL_RST_TYPE 0x01 + +#define BIOS_HOST_ADD 0x00 +#define HECI_MKHI_ADD 0x07 + +#define MAX_HECI_MESSAGE 5 +#define HECI_TIMEOUT 15000000 /* 15sec */ +#define HECI_SEND_TIMEOUT 5000000 /* 5sec */ +#define HECI_READ_TIMEOUT 5000000 /* 5sec */ +#define HECI_DELAY 1000 /* 1ms */ + +struct mei_header { + u32 client_address: 8; + u32 host_address: 8; + u32 length: 9; + u32 reserved: 6; + u32 is_complete: 1; +} __attribute__ ((packed)); + void intel_me_status(void); +int send_global_reset(void);
#endif diff --git a/src/soc/intel/skylake/me.c b/src/soc/intel/skylake/me.c new file mode 100644 index 0000000..7f62eef --- /dev/null +++ b/src/soc/intel/skylake/me.c @@ -0,0 +1,695 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2016 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <arch/io.h> +#include <console/console.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <soc/iomap.h> +#include <soc/pci_devs.h> +#include <soc/me.h> +#include <delay.h> +#include <timer.h> + +static inline void me_read_dword_ptr(void *ptr, int offset) +{ + u32 dword = pci_read_config32(PCH_DEV_ME, offset); + memcpy(ptr, &dword, sizeof(dword)); +} + +static inline void me_write_dword(int offset, u32 value) +{ + pci_write_config32(PCH_DEV_ME, offset, value); +} + +static inline void me_mmio_read_dword_ptr(void *ptr, u16 offset) +{ + u32 dword = read32((void *)(HECI1_BASE_ADDRESS + offset)); + memcpy(ptr, &dword, sizeof(dword)); +} + +static inline void me_mmio_write_dword_ptr(u16 offset, u32 value) +{ + write32((void *)(HECI1_BASE_ADDRESS + offset), value); +} + +/* HFSTS1[3:0] Current Working State Values */ +static const char *me_cws_values[] = { + [ME_HFS_CWS_RESET] = "Reset", + [ME_HFS_CWS_INIT] = "Initializing", + [ME_HFS_CWS_REC] = "Recovery", + [3] = "Unknown (3)", + [4] = "Unknown (4)", + [ME_HFS_CWS_NORMAL] = "Normal", + [ME_HFS_CWS_WAIT] = "Platform Disable Wait", + [ME_HFS_CWS_TRANS] = "OP State Transition", + [ME_HFS_CWS_INVALID] = "Invalid CPU Plugged In", + [9] = "Unknown (9)", + [10] = "Unknown (10)", + [11] = "Unknown (11)", + [12] = "Unknown (12)", + [13] = "Unknown (13)", + [14] = "Unknown (14)", + [15] = "Unknown (15)", +}; + +/* HFSTS1[8:6] Current Operation State Values */ +static const char *me_opstate_values[] = { + [ME_HFS_STATE_PREBOOT] = "Preboot", + [ME_HFS_STATE_M0_UMA] = "M0 with UMA", + [ME_HFS_STATE_M3] = "M3 without UMA", + [ME_HFS_STATE_M0] = "M0 without UMA", + [ME_HFS_STATE_BRINGUP] = "Bring up", + [ME_HFS_STATE_ERROR] = "M0 without UMA but with error" +}; + +/* HFSTS1[19:16] Current Operation Mode Values */ +static const char *me_opmode_values[] = { + [ME_HFS_MODE_NORMAL] = "Normal", + [ME_HFS_MODE_DEBUG] = "Debug", + [ME_HFS_MODE_DIS] = "Soft Temporary Disable", + [ME_HFS_MODE_OVER_JMPR] = "Security Override via Jumper", + [ME_HFS_MODE_OVER_MEI] = "Security Override via MEI Message" +}; + +/* HFSTS1[15:12] Error Code Values */ +static const char *me_error_values[] = { + [ME_HFS_ERROR_NONE] = "No Error", + [ME_HFS_ERROR_UNCAT] = "Uncategorized Failure", + [ME_HFS_ERROR_IMAGE] = "Image Failure", + [ME_HFS_ERROR_DEBUG] = "Debug Failure" +}; + +/* HFSTS2[31:28] ME Progress Code */ +static const char *me_progress_values[] = { + [ME_HFS2_PHASE_ROM] = "ROM Phase", + [1] = "Unknown (1)", + [ME_HFS2_PHASE_UKERNEL] = "uKernel Phase", + [ME_HFS2_PHASE_BUP] = "BUP Phase", + [4] = "Unknown (4)", + [5] = "Unknown (5)", + [ME_HFS2_PHASE_HOST_COMM] = "Host Communication", + [7] = "Unknown (7)", + [8] = "Unknown (8)" +}; + +/* HFSTS2[27:24] Power Management Event */ +static const char *me_pmevent_values[] = { + [ME_HFS2_PMEVENT_CLEAN_MOFF_MX_WAKE] = + "Clean Moff->Mx wake", + [ME_HFS2_PMEVENT_MOFF_MX_WAKE_ERROR] = + "Moff->Mx wake after an error", + [ME_HFS2_PMEVENT_CLEAN_GLOBAL_RESET] = + "Clean global reset", + [ME_HFS2_PMEVENT_CLEAN_GLOBAL_RESET_ERROR] = + "Global reset after an error", + [ME_HFS2_PMEVENT_CLEAN_ME_RESET] = + "Clean Intel ME reset", + [ME_HFS2_PMEVENT_ME_RESET_EXCEPTION] = + "Intel ME reset due to exception", + [ME_HFS2_PMEVENT_PSEUDO_ME_RESET] = + "Pseudo-global reset", + [ME_HFS2_PMEVENT_CM0_CM3] = + "CM0->CM3", + [ME_HFS2_PMEVENT_CM3_CM0] = + "CM3->CM0", + [ME_HFS2_PMEVENT_NON_PWR_CYCLE_RESET] = + "Non-power cycle reset", + [ME_HFS2_PMEVENT_PWR_CYCLE_RESET_M3] = + "Power cycle reset through M3", + [ME_HFS2_PMEVENT_PWR_CYCLE_RESET_MOFF] = + "Power cycle reset through Moff", + [ME_HFS2_PMEVENT_CMX_CMOFF] = + "Cx/Mx->Cx/Moff", + [ME_HFS2_PMEVENT_CM0_CM0PG] = + "CM0->CM0PG", + [ME_HFS2_PMEVENT_CM3_CM3PG] = + "CM3->CM3PG", + [ME_HFS2_PMEVENT_CM0PG_CM0] = + "CM0PG->CM0" + +}; + +/* Progress Code 0 states */ +static const char *me_progress_rom_values[] = { + [ME_HFS2_STATE_ROM_BEGIN] = "BEGIN", + [ME_HFS2_STATE_ROM_DISABLE] = "DISABLE" +}; + +/* Progress Code 1 states */ +static const char *me_progress_bup_values[] = { + [ME_HFS2_STATE_BUP_INIT] = + "Initialization starts", + [ME_HFS2_STATE_BUP_DIS_HOST_WAKE] = + "Disable the host wake event", + [ME_HFS2_STATE_BUP_CG_ENABLE] = + "Enabling CG for cset", + [ME_HFS2_STATE_BUP_PM_HND_EN] = + "Enabling PM handshaking", + [ME_HFS2_STATE_BUP_FLOW_DET] = + "Flow determination start process", + [ME_HFS2_STATE_BUP_PMC_PATCHING] = + "PMC Patching process", + [ME_HFS2_STATE_BUP_GET_FLASH_VSCC] = + "Get VSCC params", + [ME_HFS2_STATE_BUP_SET_FLASH_VSCC] = + "Set VSCC params", + [ME_HFS2_STATE_BUP_VSCC_ERR] = + "Error reading/matching the VSCC table in the descriptor", + [ME_HFS2_STATE_BUP_EFSS_INIT] = + "Initialize EFFS", + [ME_HFS2_STATE_BUP_CHECK_STRAP] = + "Check to see if straps say ME DISABLED", + [ME_HFS2_STATE_BUP_PWR_OK_TIMEOUT] = + "Timeout waiting for PWROK", + [ME_HFS2_STATE_BUP_STRAP_DIS] = + "EFFS says ME disabled", + [ME_HFS2_STATE_BUP_MANUF_OVRD_STRAP] = + "Possibly handle BUP manufacturing override strap", + [ME_HFS2_STATE_BUP_M3] = + "Bringup in M3", + [ME_HFS2_STATE_BUP_M0] = + "Bringup in M0", + [ME_HFS2_STATE_BUP_FLOW_DET_ERR] = + "Flow detection error", + [ME_HFS2_STATE_BUP_M3_CLK_ERR] = + "M3 clock switching error", + [ME_HFS2_STATE_BUP_CPU_RESET_DID_TIMEOUT_MEM_MISSING] = + "Host error - CPU reset timeout, DID timeout, memory missing", + [ME_HFS2_STATE_BUP_M3_KERN_LOAD] = + "M3 kernel load", + [ME_HFS2_STATE_BUP_T32_MISSING] = + "T34 missing - cannot program ICC", + [ME_HFS2_STATE_BUP_WAIT_DID] = + "Waiting for DID BIOS message", + [ME_HFS2_STATE_BUP_WAIT_DID_FAIL] = + "Waiting for DID BIOS message failure", + [ME_HFS2_STATE_BUP_DID_NO_FAIL] = + "DID reported no error", + [ME_HFS2_STATE_BUP_ENABLE_UMA] = + "Enabling UMA", + [ME_HFS2_STATE_BUP_ENABLE_UMA_ERR] = + "Enabling UMA error", + [ME_HFS2_STATE_BUP_SEND_DID_ACK] = + "Sending DID Ack to BIOS", + [ME_HFS2_STATE_BUP_SEND_DID_ACK_ERR] = + "Sending DID Ack to BIOS error", + [ME_HFS2_STATE_BUP_M0_CLK] = + "Switching clocks in M0", + [ME_HFS2_STATE_BUP_M0_CLK_ERR] = + "Switching clocks in M0 error", + [ME_HFS2_STATE_BUP_TEMP_DIS] = + "ME in temp disable", + [ME_HFS2_STATE_BUP_M0_KERN_LOAD] = + "M0 kernel load", +}; + +void intel_me_status(void) +{ + struct me_hfs _hfs, *hfs = &_hfs; + struct me_hfs2 _hfs2, *hfs2 = &_hfs2; + struct me_hfs3 _hfs3, *hfs3 = &_hfs3; + + me_read_dword_ptr(hfs, PCI_ME_HFSTS1); + me_read_dword_ptr(hfs2, PCI_ME_HFSTS2); + me_read_dword_ptr(hfs3, PCI_ME_HFSTS3); + + /* Check Current States */ + printk(BIOS_DEBUG, "ME: FW Partition Table : %s\n", + hfs->fpt_bad ? "BAD" : "OK"); + printk(BIOS_DEBUG, "ME: Bringup Loader Failure : %s\n", + hfs->ft_bup_ld_flr ? "YES" : "NO"); + printk(BIOS_DEBUG, "ME: Firmware Init Complete : %s\n", + hfs->fw_init_complete ? "YES" : "NO"); + printk(BIOS_DEBUG, "ME: Manufacturing Mode : %s\n", + hfs->mfg_mode ? "YES" : "NO"); + printk(BIOS_DEBUG, "ME: Boot Options Present : %s\n", + hfs->boot_options_present ? "YES" : "NO"); + printk(BIOS_DEBUG, "ME: Update In Progress : %s\n", + hfs->update_in_progress ? "YES" : "NO"); + printk(BIOS_DEBUG, "ME: D3 Support : %s\n", + hfs->d3_support_valid ? "YES" : "NO"); + printk(BIOS_DEBUG, "ME: D0i3 Support : %s\n", + hfs->d0i3_support_valid ? "YES" : "NO"); + printk(BIOS_DEBUG, "ME: Low Power State Enabled : %s\n", + hfs2->low_power_state ? "YES" : "NO"); + printk(BIOS_DEBUG, "ME: Power Gated : %s\n", + hfs2->power_gating_ind ? "YES" : "NO"); + printk(BIOS_DEBUG, "ME: CPU Replaced : %s\n", + hfs2->cpu_replaced_sts ? "YES" : "NO"); + printk(BIOS_DEBUG, "ME: CPU Replacement Valid : %s\n", + hfs2->cpu_replaced_valid ? "YES" : "NO"); + printk(BIOS_DEBUG, "ME: Current Working State : %s\n", + me_cws_values[hfs->working_state]); + printk(BIOS_DEBUG, "ME: Current Operation State : %s\n", + me_opstate_values[hfs->operation_state]); + printk(BIOS_DEBUG, "ME: Current Operation Mode : %s\n", + me_opmode_values[hfs->operation_mode]); + printk(BIOS_DEBUG, "ME: Error Code : %s\n", + me_error_values[hfs->error_code]); + printk(BIOS_DEBUG, "ME: Progress Phase : %s\n", + me_progress_values[hfs2->progress_code]); + printk(BIOS_DEBUG, "ME: Power Management Event : %s\n", + me_pmevent_values[hfs2->current_pmevent]); + + printk(BIOS_DEBUG, "ME: Progress Phase State : "); + switch (hfs2->progress_code) { + case ME_HFS2_PHASE_ROM: /* ROM Phase */ + printk(BIOS_DEBUG, "%s", + me_progress_rom_values[hfs2->current_state]); + break; + + case ME_HFS2_PHASE_UKERNEL: /* uKernel Phase */ + printk(BIOS_DEBUG, "0x%02x", hfs2->current_state); + break; + + case ME_HFS2_PHASE_BUP: /* Bringup Phase */ + if (hfs2->current_state < ARRAY_SIZE(me_progress_bup_values) + && me_progress_bup_values[hfs2->current_state]) + printk(BIOS_DEBUG, "%s", + me_progress_bup_values[hfs2->current_state]); + else + printk(BIOS_DEBUG, "0x%02x", hfs2->current_state); + break; + + case ME_HFS2_PHASE_HOST_COMM: /* Host Communication Phase */ + if (!hfs2->current_state) + printk(BIOS_DEBUG, "Host communication established"); + else + printk(BIOS_DEBUG, "0x%02x", hfs2->current_state); + break; + + default: + printk(BIOS_DEBUG, "Unknown phase: 0x%02x state: 0x%02x", + hfs2->progress_code, hfs2->current_state); + } + printk(BIOS_DEBUG, "\n"); + + /* Power Down Mitigation Status */ + printk(BIOS_DEBUG, "ME: Power Down Mitigation : %s\n", + hfs3->power_down_mitigation ? "YES" : "NO"); + + if (hfs3->power_down_mitigation) { + printk(BIOS_INFO, "ME: PD Mitigation State : "); + if (hfs3->encrypt_key_override == 1 && + hfs3->encrypt_key_check == 0 && + hfs3->pch_config_change == 0) + printk(BIOS_INFO, "Normal Operation"); + else if (hfs3->encrypt_key_override == 1 && + hfs3->encrypt_key_check == 1 && + hfs3->pch_config_change == 0) + printk(BIOS_INFO, "Issue Detected and Recovered"); + else + printk(BIOS_INFO, "Issue Detected but not Recovered"); + printk(BIOS_INFO, "\n"); + + printk(BIOS_DEBUG, "ME: Encryption Key Override : %s\n", + hfs3->encrypt_key_override ? "Workaround Applied" : + "Unable to override"); + printk(BIOS_DEBUG, "ME: Encryption Key Check : %s\n", + hfs3->encrypt_key_check ? "FAIL" : "PASS"); + printk(BIOS_DEBUG, "ME: PCH Configuration Info : %s\n", + hfs3->pch_config_change ? "Changed" : "No Change"); + + printk(BIOS_DEBUG, "ME: Firmware SKU : "); + switch (hfs3->fw_sku) { + case ME_HFS3_FW_SKU_CONSUMER: + printk(BIOS_DEBUG, "Consumer\n"); + break; + case ME_HFS3_FW_SKU_CORPORATE: + printk(BIOS_DEBUG, "Corporate\n"); + break; + default: + printk(BIOS_DEBUG, "Unknown (0x%x)\n", hfs3->fw_sku); + } + } +} +static int wait_heci_ready(void) +{ + struct stopwatch sw; + int timeout = 0; + struct me_csr _csr, *csr = &_csr; + + stopwatch_init_msecs_expire(&sw, HECI_TIMEOUT); + while (1) { + do { + me_mmio_read_dword_ptr(csr, MMIO_ME_CSR); + if (csr->host_ready) + return 0; + } while (!(timeout = stopwatch_expired(&sw))); + + if (timeout) { + printk(BIOS_ERR, + "ME_RDY bit is not set after 15 sec"); + return -1; + } + udelay(HECI_DELAY); + } +} + +static int wait_heci_cb_avail(int len) +{ + struct stopwatch sw; + int timeout = 0; + struct host_csr _csr, *csr = &_csr; + + me_mmio_read_dword_ptr(csr, MMIO_HOST_CSR); + /* + * if timeout has happend, return failure as + * the circular buffer is not empty + */ + stopwatch_init_msecs_expire(&sw, HECI_SEND_TIMEOUT); + /* Must have room for message and message header */ + while (len > (csr->me_cir_depth - (csr->host_write_ptr - + csr->host_read_ptr))) { + timeout = stopwatch_expired(&sw); + + if (timeout) { + printk(BIOS_ERR, + "Circular Buffer never emptied within 5 sec"); + return -1; + } + /* wait before trying again */ + udelay(HECI_DELAY); + /* read HOST_CSR for next iteration */ + me_mmio_read_dword_ptr(csr, MMIO_HOST_CSR); + } + return 0; +} + +static int send_heci_packet(struct mei_header *head, u32 * payload) +{ + /* compute the message lenth in dwords */ + int len = (head->length + 3) / 4; + int sts; + int index; + struct me_csr _csr, *csr = &_csr; + struct host_csr _hcsr, *hcsr = &_hcsr; + + /* + * wait until there is sufficient room in CB + */ + sts = wait_heci_cb_avail(len+1); + if (sts != 0) + return -1; + + /* Write message header */ + me_mmio_write_dword_ptr(MMIO_ME_CB_WW, *(u32 *) head); + + /* Write message body */ + for (index = 0; index < len; index++) + me_mmio_write_dword_ptr(MMIO_ME_CB_WW, payload[index]); + + /* Set Interrupt Generate bit */ + me_mmio_read_dword_ptr(hcsr, MMIO_HOST_CSR); + hcsr->int_gen = 1; + me_mmio_write_dword_ptr(MMIO_HOST_CSR, *(u32 *) hcsr); + + /* Check if ME Ready bit is set, if set to 0 then return fatal error */ + me_mmio_read_dword_ptr(csr, MMIO_ME_CSR); + if (csr->host_ready) + return 0; + else + return -1; +} + +static int recv_heci_packet(struct mei_header *head, u32 * packet, + u32 * packet_size) +{ + struct me_csr _csr, *csr = &_csr; + struct host_csr _hcsr, *hcsr = &_hcsr; + int rec_msg = 0; + struct stopwatch sw; + int timeout = 0; + u32 length, index; + + /* Clear Interrupt Status bit */ + me_mmio_read_dword_ptr(hcsr, MMIO_HOST_CSR); + hcsr->int_sts = 1; + me_mmio_write_dword_ptr(MMIO_HOST_CSR, *(u32 *) hcsr); + + /* Check if circular buffer overflow */ + me_mmio_read_dword_ptr(csr, MMIO_ME_CSR); + /* if yes then return fatal error */ + if ((csr->me_write_ptr - csr->me_read_ptr) > csr->me_cir_buff) + return -1; + /* + * if timeout has happend, return failure as + * the circular buffer is not empty + */ + stopwatch_init_msecs_expire(&sw, HECI_READ_TIMEOUT); + /* go until we got message pkt */ + do { + timeout = stopwatch_expired(&sw); + + if (timeout) { + printk(BIOS_ERR, + "Circular Buffer not filled within 5 sec"); + *packet_size = 0; + return -1; + } + me_mmio_read_dword_ptr(csr, MMIO_ME_CSR); + /* Read one message from HECI buffer */ + if ((csr->me_write_ptr - csr->me_read_ptr) > 0) { + me_mmio_read_dword_ptr(head, MMIO_ME_CB_RW); + /* calculate the message length in dword */ + length = ((head->length + 3) / 4); + if (head->length == 0) { + *packet_size = 0; + goto SET_IG; + } + /* Make sure, we have enough space to catch all */ + if (head->length <= *packet_size) { + me_mmio_read_dword_ptr(csr, MMIO_ME_CSR); + /* get complete message into circular buffer */ + while (length > (csr->me_write_ptr - + csr->me_read_ptr)) { + udelay(HECI_DELAY); + me_mmio_read_dword_ptr(csr, + MMIO_ME_CSR); + } + /* here is the message */ + for (index = 0; index < length; index++) { + packet[index] = read32( + (void *)(HECI1_BASE_ADDRESS + + MMIO_ME_CB_RW)); + } + rec_msg = 1; + *packet_size = head->length; + } else { + /* Too small buffer */ + *packet_size = 0; + return -1; + } + } + udelay(HECI_DELAY); + } while (!rec_msg); + + /* + * Check if ME Ready bit is set, if set to 0 then return fatal error + * because ME might have reset during transaction and we might have + * read a junk data from CB + */ + me_mmio_read_dword_ptr(csr, MMIO_ME_CSR); + if (!(csr->host_ready)) + return -1; +SET_IG: + /* Set Interrupt Generate bit */ + me_mmio_read_dword_ptr(hcsr, MMIO_HOST_CSR); + hcsr->int_gen = 1; + me_mmio_write_dword_ptr(MMIO_HOST_CSR, *(u32 *) hcsr); + return 0; +} + +static int +send_heci_message(u8 * msg, int len, u8 hostaddress, u8 clientaddress) +{ + u8 retry; + int status = -1; + u32 cir_buff_depth; + struct host_csr _csr, *csr = &_csr; + struct mei_header head; + int cur = 0; + u32 slength; + + for (retry = 0; retry < MAX_HECI_MESSAGE; retry++) { + if (wait_heci_ready() != 0) + continue; + /* HECI is ready */ + me_mmio_read_dword_ptr(csr, MMIO_HOST_CSR); + cir_buff_depth = csr->me_cir_depth; + head.client_address = clientaddress; + head.host_address = hostaddress; + while (len > cur) { + /* + * Set the message complete bit if this is last packet + * in message needs to be "less than" to account for + * the header OR needs to be exact equal to CB depth + */ + if (((((len - cur) + 3) / 4) < cir_buff_depth) || + (((((len - cur) + 3) / 4) == + cir_buff_depth) && + ((((len - cur) + 3) % 4) == 0))) + head.is_complete = 1; + else + head.is_complete = 0; + /* + * calculate length for message header + * header length = smaller of CB buffer or + * remaining message + */ + slength = ((cir_buff_depth <= (((len - cur) + 3) / 4)) + ? ((cir_buff_depth - 1) * 4) + : (len - cur)); + head.length = slength; + head.reserved = 0; + /* + * send the current packet + * (cur should be treated as index for message) + */ + status = send_heci_packet(&head, (u32 *) msg); + if (status != 0) + break; + /* update the length information */ + cur += slength; + msg += cur; + } + if (status != 0) + continue; + else + return status; + } + return status; +} + +static int +recv_heci_message(u32 * message, u32 * message_size) +{ + struct mei_header head; + int cur = 0; + u8 retry; + int status = -1; + int msg_complete = 0; + u32 pkt_buff; + + for (retry = 0; retry < MAX_HECI_MESSAGE; retry++) { + if (wait_heci_ready() != 0) + continue; + /* HECI is ready */ + while ((cur < *message_size) && (msg_complete == 0)) + { + pkt_buff = *message_size - cur; + status = recv_heci_packet(&head, message + (cur >> 2), + &pkt_buff); + if (status == -1) { + *message_size = 0; + break; + } + msg_complete = head.is_complete; + if (pkt_buff == 0) { + /* if not in middle of msg and msg complete bit + * is set then this is a valid zero length msg + */ + if ((cur == 0) && (msg_complete == 1)) + status = 0; + else + status = -1; + *message_size = 0; + break; + } + cur += pkt_buff; + } + if (status != 0) + continue; + else { + *message_size = cur; + break; + } + } + return status; +} + +static int send_heci_reset_message(void) +{ + int status; + struct reset_reply { + u8 group_id; + u8 command; + u8 reserved; + u8 result; + } __attribute__ ((packed)) reply; + struct reset_message { + u8 group_id; + u8 cmd; + u8 reserved; + u8 result; + u8 req_origin; + u8 reset_type; + } __attribute__ ((packed)) msg = { + 0, MKHI_GLOBAL_RESET, 0, 0, + GR_ORIGIN_BIOS_POST, GLOBAL_RST_TYPE}; + u32 reply_size; + + status= send_heci_message((u8 *) & msg, sizeof(msg), + BIOS_HOST_ADD, HECI_MKHI_ADD); + if (status != 0) + return -1; + + reply_size = sizeof(reply); + if (recv_heci_message((u32 *) & reply, &reply_size) == -1) + return -1; + /*get reply result from HECI MSG */ + if (reply.result != 0) { + printk(BIOS_DEBUG, "%s: Exit with Failure\n", __func__); + return -1; + } else { + printk(BIOS_DEBUG, "%s: Exit with Success\n", __func__); + return 0; + } +} + +int send_global_reset(void) +{ + u32 heci1_bar; + u32 heci1_cmdsts; + int status = -1; + struct me_hfs _hfs, *hfs = &_hfs; + + /* Check HECI1 BAR gets programmed */ + me_read_dword_ptr(&heci1_bar, PCI_ME_BAR); + heci1_bar &= ~0xfff; + if (heci1_bar != HECI1_BASE_ADDRESS) { + /* use default HECI BAR for SoC */ + me_write_dword(PCI_ME_BAR, HECI1_BASE_ADDRESS); + } + /* Check MMIO space & Bus master enabled */ + me_read_dword_ptr(&heci1_cmdsts, PCI_ME_CMDSTS); + if ((heci1_cmdsts & (ME_CMDSTS_MSE | ME_CMDSTS_BME)) != + (ME_CMDSTS_MSE | ME_CMDSTS_BME)) { + me_write_dword(PCI_ME_CMDSTS, ME_CMDSTS_MSE | ME_CMDSTS_BME); + } + /* Check ME operating mode */ + me_read_dword_ptr(hfs, PCI_ME_HFSTS1); + if (hfs->operation_mode) { + goto ret; + } + /* ME should be in Normal Mode for this command */ + status = send_heci_reset_message(); +ret: + return status; +} diff --git a/src/soc/intel/skylake/me_status.c b/src/soc/intel/skylake/me_status.c deleted file mode 100644 index 79d4dfb..0000000 --- a/src/soc/intel/skylake/me_status.c +++ /dev/null @@ -1,324 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2008-2009 coresystems GmbH - * Copyright (C) 2014 Google Inc. - * Copyright (C) 2016 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <arch/io.h> -#include <console/console.h> -#include <device/pci.h> -#include <device/pci_ids.h> -#include <stdlib.h> -#include <string.h> -#include <soc/pci_devs.h> -#include <soc/me.h> -#include <delay.h> - -static inline void me_read_dword_ptr(void *ptr, int offset) -{ - u32 dword = pci_read_config32(PCH_DEV_ME, offset); - memcpy(ptr, &dword, sizeof(dword)); -} - -/* HFSTS1[3:0] Current Working State Values */ -static const char *me_cws_values[] = { - [ME_HFS_CWS_RESET] = "Reset", - [ME_HFS_CWS_INIT] = "Initializing", - [ME_HFS_CWS_REC] = "Recovery", - [3] = "Unknown (3)", - [4] = "Unknown (4)", - [ME_HFS_CWS_NORMAL] = "Normal", - [ME_HFS_CWS_WAIT] = "Platform Disable Wait", - [ME_HFS_CWS_TRANS] = "OP State Transition", - [ME_HFS_CWS_INVALID] = "Invalid CPU Plugged In", - [9] = "Unknown (9)", - [10] = "Unknown (10)", - [11] = "Unknown (11)", - [12] = "Unknown (12)", - [13] = "Unknown (13)", - [14] = "Unknown (14)", - [15] = "Unknown (15)", -}; - -/* HFSTS1[8:6] Current Operation State Values */ -static const char *me_opstate_values[] = { - [ME_HFS_STATE_PREBOOT] = "Preboot", - [ME_HFS_STATE_M0_UMA] = "M0 with UMA", - [ME_HFS_STATE_M3] = "M3 without UMA", - [ME_HFS_STATE_M0] = "M0 without UMA", - [ME_HFS_STATE_BRINGUP] = "Bring up", - [ME_HFS_STATE_ERROR] = "M0 without UMA but with error" -}; - -/* HFSTS1[19:16] Current Operation Mode Values */ -static const char *me_opmode_values[] = { - [ME_HFS_MODE_NORMAL] = "Normal", - [ME_HFS_MODE_DEBUG] = "Debug", - [ME_HFS_MODE_DIS] = "Soft Temporary Disable", - [ME_HFS_MODE_OVER_JMPR] = "Security Override via Jumper", - [ME_HFS_MODE_OVER_MEI] = "Security Override via MEI Message" -}; - -/* HFSTS1[15:12] Error Code Values */ -static const char *me_error_values[] = { - [ME_HFS_ERROR_NONE] = "No Error", - [ME_HFS_ERROR_UNCAT] = "Uncategorized Failure", - [ME_HFS_ERROR_IMAGE] = "Image Failure", - [ME_HFS_ERROR_DEBUG] = "Debug Failure" -}; - -/* HFSTS2[31:28] ME Progress Code */ -static const char *me_progress_values[] = { - [ME_HFS2_PHASE_ROM] = "ROM Phase", - [1] = "Unknown (1)", - [ME_HFS2_PHASE_UKERNEL] = "uKernel Phase", - [ME_HFS2_PHASE_BUP] = "BUP Phase", - [4] = "Unknown (4)", - [5] = "Unknown (5)", - [ME_HFS2_PHASE_HOST_COMM] = "Host Communication", - [7] = "Unknown (7)", - [8] = "Unknown (8)" -}; - -/* HFSTS2[27:24] Power Management Event */ -static const char *me_pmevent_values[] = { - [ME_HFS2_PMEVENT_CLEAN_MOFF_MX_WAKE] = - "Clean Moff->Mx wake", - [ME_HFS2_PMEVENT_MOFF_MX_WAKE_ERROR] = - "Moff->Mx wake after an error", - [ME_HFS2_PMEVENT_CLEAN_GLOBAL_RESET] = - "Clean global reset", - [ME_HFS2_PMEVENT_CLEAN_GLOBAL_RESET_ERROR] = - "Global reset after an error", - [ME_HFS2_PMEVENT_CLEAN_ME_RESET] = - "Clean Intel ME reset", - [ME_HFS2_PMEVENT_ME_RESET_EXCEPTION] = - "Intel ME reset due to exception", - [ME_HFS2_PMEVENT_PSEUDO_ME_RESET] = - "Pseudo-global reset", - [ME_HFS2_PMEVENT_CM0_CM3] = - "CM0->CM3", - [ME_HFS2_PMEVENT_CM3_CM0] = - "CM3->CM0", - [ME_HFS2_PMEVENT_NON_PWR_CYCLE_RESET] = - "Non-power cycle reset", - [ME_HFS2_PMEVENT_PWR_CYCLE_RESET_M3] = - "Power cycle reset through M3", - [ME_HFS2_PMEVENT_PWR_CYCLE_RESET_MOFF] = - "Power cycle reset through Moff", - [ME_HFS2_PMEVENT_CMX_CMOFF] = - "Cx/Mx->Cx/Moff", - [ME_HFS2_PMEVENT_CM0_CM0PG] = - "CM0->CM0PG", - [ME_HFS2_PMEVENT_CM3_CM3PG] = - "CM3->CM3PG", - [ME_HFS2_PMEVENT_CM0PG_CM0] = - "CM0PG->CM0" - -}; - -/* Progress Code 0 states */ -static const char *me_progress_rom_values[] = { - [ME_HFS2_STATE_ROM_BEGIN] = "BEGIN", - [ME_HFS2_STATE_ROM_DISABLE] = "DISABLE" -}; - -/* Progress Code 1 states */ -static const char *me_progress_bup_values[] = { - [ME_HFS2_STATE_BUP_INIT] = - "Initialization starts", - [ME_HFS2_STATE_BUP_DIS_HOST_WAKE] = - "Disable the host wake event", - [ME_HFS2_STATE_BUP_CG_ENABLE] = - "Enabling CG for cset", - [ME_HFS2_STATE_BUP_PM_HND_EN] = - "Enabling PM handshaking", - [ME_HFS2_STATE_BUP_FLOW_DET] = - "Flow determination start process", - [ME_HFS2_STATE_BUP_PMC_PATCHING] = - "PMC Patching process", - [ME_HFS2_STATE_BUP_GET_FLASH_VSCC] = - "Get VSCC params", - [ME_HFS2_STATE_BUP_SET_FLASH_VSCC] = - "Set VSCC params", - [ME_HFS2_STATE_BUP_VSCC_ERR] = - "Error reading/matching the VSCC table in the descriptor", - [ME_HFS2_STATE_BUP_EFSS_INIT] = - "Initialize EFFS", - [ME_HFS2_STATE_BUP_CHECK_STRAP] = - "Check to see if straps say ME DISABLED", - [ME_HFS2_STATE_BUP_PWR_OK_TIMEOUT] = - "Timeout waiting for PWROK", - [ME_HFS2_STATE_BUP_STRAP_DIS] = - "EFFS says ME disabled", - [ME_HFS2_STATE_BUP_MANUF_OVRD_STRAP] = - "Possibly handle BUP manufacturing override strap", - [ME_HFS2_STATE_BUP_M3] = - "Bringup in M3", - [ME_HFS2_STATE_BUP_M0] = - "Bringup in M0", - [ME_HFS2_STATE_BUP_FLOW_DET_ERR] = - "Flow detection error", - [ME_HFS2_STATE_BUP_M3_CLK_ERR] = - "M3 clock switching error", - [ME_HFS2_STATE_BUP_CPU_RESET_DID_TIMEOUT_MEM_MISSING] = - "Host error - CPU reset timeout, DID timeout, memory missing", - [ME_HFS2_STATE_BUP_M3_KERN_LOAD] = - "M3 kernel load", - [ME_HFS2_STATE_BUP_T32_MISSING] = - "T34 missing - cannot program ICC", - [ME_HFS2_STATE_BUP_WAIT_DID] = - "Waiting for DID BIOS message", - [ME_HFS2_STATE_BUP_WAIT_DID_FAIL] = - "Waiting for DID BIOS message failure", - [ME_HFS2_STATE_BUP_DID_NO_FAIL] = - "DID reported no error", - [ME_HFS2_STATE_BUP_ENABLE_UMA] = - "Enabling UMA", - [ME_HFS2_STATE_BUP_ENABLE_UMA_ERR] = - "Enabling UMA error", - [ME_HFS2_STATE_BUP_SEND_DID_ACK] = - "Sending DID Ack to BIOS", - [ME_HFS2_STATE_BUP_SEND_DID_ACK_ERR] = - "Sending DID Ack to BIOS error", - [ME_HFS2_STATE_BUP_M0_CLK] = - "Switching clocks in M0", - [ME_HFS2_STATE_BUP_M0_CLK_ERR] = - "Switching clocks in M0 error", - [ME_HFS2_STATE_BUP_TEMP_DIS] = - "ME in temp disable", - [ME_HFS2_STATE_BUP_M0_KERN_LOAD] = - "M0 kernel load", -}; - -void intel_me_status(void) -{ - struct me_hfs _hfs, *hfs = &_hfs; - struct me_hfs2 _hfs2, *hfs2 = &_hfs2; - struct me_hfs3 _hfs3, *hfs3 = &_hfs3; - - me_read_dword_ptr(hfs, PCI_ME_HFSTS1); - me_read_dword_ptr(hfs2, PCI_ME_HFSTS2); - me_read_dword_ptr(hfs3, PCI_ME_HFSTS3); - - /* Check Current States */ - printk(BIOS_DEBUG, "ME: FW Partition Table : %s\n", - hfs->fpt_bad ? "BAD" : "OK"); - printk(BIOS_DEBUG, "ME: Bringup Loader Failure : %s\n", - hfs->ft_bup_ld_flr ? "YES" : "NO"); - printk(BIOS_DEBUG, "ME: Firmware Init Complete : %s\n", - hfs->fw_init_complete ? "YES" : "NO"); - printk(BIOS_DEBUG, "ME: Manufacturing Mode : %s\n", - hfs->mfg_mode ? "YES" : "NO"); - printk(BIOS_DEBUG, "ME: Boot Options Present : %s\n", - hfs->boot_options_present ? "YES" : "NO"); - printk(BIOS_DEBUG, "ME: Update In Progress : %s\n", - hfs->update_in_progress ? "YES" : "NO"); - printk(BIOS_DEBUG, "ME: D3 Support : %s\n", - hfs->d3_support_valid ? "YES" : "NO"); - printk(BIOS_DEBUG, "ME: D0i3 Support : %s\n", - hfs->d0i3_support_valid ? "YES" : "NO"); - printk(BIOS_DEBUG, "ME: Low Power State Enabled : %s\n", - hfs2->low_power_state ? "YES" : "NO"); - printk(BIOS_DEBUG, "ME: Power Gated : %s\n", - hfs2->power_gating_ind ? "YES" : "NO"); - printk(BIOS_DEBUG, "ME: CPU Replaced : %s\n", - hfs2->cpu_replaced_sts ? "YES" : "NO"); - printk(BIOS_DEBUG, "ME: CPU Replacement Valid : %s\n", - hfs2->cpu_replaced_valid ? "YES" : "NO"); - printk(BIOS_DEBUG, "ME: Current Working State : %s\n", - me_cws_values[hfs->working_state]); - printk(BIOS_DEBUG, "ME: Current Operation State : %s\n", - me_opstate_values[hfs->operation_state]); - printk(BIOS_DEBUG, "ME: Current Operation Mode : %s\n", - me_opmode_values[hfs->operation_mode]); - printk(BIOS_DEBUG, "ME: Error Code : %s\n", - me_error_values[hfs->error_code]); - printk(BIOS_DEBUG, "ME: Progress Phase : %s\n", - me_progress_values[hfs2->progress_code]); - printk(BIOS_DEBUG, "ME: Power Management Event : %s\n", - me_pmevent_values[hfs2->current_pmevent]); - - printk(BIOS_DEBUG, "ME: Progress Phase State : "); - switch (hfs2->progress_code) { - case ME_HFS2_PHASE_ROM: /* ROM Phase */ - printk(BIOS_DEBUG, "%s", - me_progress_rom_values[hfs2->current_state]); - break; - - case ME_HFS2_PHASE_UKERNEL: /* uKernel Phase */ - printk(BIOS_DEBUG, "0x%02x", hfs2->current_state); - break; - - case ME_HFS2_PHASE_BUP: /* Bringup Phase */ - if (hfs2->current_state < ARRAY_SIZE(me_progress_bup_values) - && me_progress_bup_values[hfs2->current_state]) - printk(BIOS_DEBUG, "%s", - me_progress_bup_values[hfs2->current_state]); - else - printk(BIOS_DEBUG, "0x%02x", hfs2->current_state); - break; - - case ME_HFS2_PHASE_HOST_COMM: /* Host Communication Phase */ - if (!hfs2->current_state) - printk(BIOS_DEBUG, "Host communication established"); - else - printk(BIOS_DEBUG, "0x%02x", hfs2->current_state); - break; - - default: - printk(BIOS_DEBUG, "Unknown phase: 0x%02x state: 0x%02x", - hfs2->progress_code, hfs2->current_state); - } - printk(BIOS_DEBUG, "\n"); - - /* Power Down Mitigation Status */ - printk(BIOS_DEBUG, "ME: Power Down Mitigation : %s\n", - hfs3->power_down_mitigation ? "YES" : "NO"); - - if (hfs3->power_down_mitigation) { - printk(BIOS_INFO, "ME: PD Mitigation State : "); - if (hfs3->encrypt_key_override == 1 && - hfs3->encrypt_key_check == 0 && - hfs3->pch_config_change == 0) - printk(BIOS_INFO, "Normal Operation"); - else if (hfs3->encrypt_key_override == 1 && - hfs3->encrypt_key_check == 1 && - hfs3->pch_config_change == 0) - printk(BIOS_INFO, "Issue Detected and Recovered"); - else - printk(BIOS_INFO, "Issue Detected but not Recovered"); - printk(BIOS_INFO, "\n"); - - printk(BIOS_DEBUG, "ME: Encryption Key Override : %s\n", - hfs3->encrypt_key_override ? "Workaround Applied" : - "Unable to override"); - printk(BIOS_DEBUG, "ME: Encryption Key Check : %s\n", - hfs3->encrypt_key_check ? "FAIL" : "PASS"); - printk(BIOS_DEBUG, "ME: PCH Configuration Info : %s\n", - hfs3->pch_config_change ? "Changed" : "No Change"); - - printk(BIOS_DEBUG, "ME: Firmware SKU : "); - switch (hfs3->fw_sku) { - case ME_HFS3_FW_SKU_CONSUMER: - printk(BIOS_DEBUG, "Consumer\n"); - break; - case ME_HFS3_FW_SKU_CORPORATE: - printk(BIOS_DEBUG, "Corporate\n"); - break; - default: - printk(BIOS_DEBUG, "Unknown (0x%x)\n", hfs3->fw_sku); - } - } -}