From 3d299c4b092d3464ea90ddc338f62b04a61e0c46 Mon Sep 17 00:00:00 2001 From: Duncan Laurie Date: Fri, 19 Jul 2013 08:48:05 -0700 Subject: [PATCH] lynxpoint me: add support for mbp clear wait in finalize step The management engine is slow, requiring at least 500ms between when the Dram Init Done message is sent (right after memory training) to when the MBP will report that it is successfully cleared and that the ME can finally be sent the EOP message. Currently this is adding 100-150ms to the boot time. If we defer waiting for the MBP Clear indicator until the finalize step we can gain back that lost time. boot on falco with SMI debugging enabled to ensure that the ME is locked down in the finalize step: Finalizing Coreboot SMI# #0 SMI_STS: PM1 APM ME: MBP cleared ME: mkhi_end_of_post ME: END OF POST message successful (0) Change-Id: Icab4c8c8e00eea67bed5e8154d91a1eb48a492d1 Signed-off-by: Duncan Laurie Reviewed-on: https://gerrit.chromium.org/gerrit/62633 Reviewed-by: Aaron Durbin Reviewed-on: http://review.coreboot.org/4375 Tested-by: build bot (Jenkins) Reviewed-by: Patrick Georgi --- src/mainboard/google/slippy/smihandler.c | 1 - .../intel/baskingridge/mainboard_smi.c | 1 - src/mainboard/intel/wtm2/mainboard_smi.c | 1 - src/southbridge/intel/lynxpoint/Kconfig | 9 +++ src/southbridge/intel/lynxpoint/finalize.c | 4 + src/southbridge/intel/lynxpoint/me_9.x.c | 81 ++++++++++++------- 6 files changed, 63 insertions(+), 34 deletions(-) diff --git a/src/mainboard/google/slippy/smihandler.c b/src/mainboard/google/slippy/smihandler.c index 428af5f5c5..7b7dd69beb 100644 --- a/src/mainboard/google/slippy/smihandler.c +++ b/src/mainboard/google/slippy/smihandler.c @@ -133,7 +133,6 @@ int mainboard_smi_apmc(u8 apmc) return 0; } - intel_me_finalize_smm(); intel_pch_finalize_smm(); intel_northbridge_haswell_finalize_smm(); intel_cpu_haswell_finalize_smm(); diff --git a/src/mainboard/intel/baskingridge/mainboard_smi.c b/src/mainboard/intel/baskingridge/mainboard_smi.c index e543494b25..f24af67579 100644 --- a/src/mainboard/intel/baskingridge/mainboard_smi.c +++ b/src/mainboard/intel/baskingridge/mainboard_smi.c @@ -84,7 +84,6 @@ int mainboard_smi_apmc(u8 apmc) return 0; } - intel_me_finalize_smm(); intel_pch_finalize_smm(); intel_northbridge_haswell_finalize_smm(); intel_cpu_haswell_finalize_smm(); diff --git a/src/mainboard/intel/wtm2/mainboard_smi.c b/src/mainboard/intel/wtm2/mainboard_smi.c index 3ffc68441d..bcc94d6f2b 100644 --- a/src/mainboard/intel/wtm2/mainboard_smi.c +++ b/src/mainboard/intel/wtm2/mainboard_smi.c @@ -60,7 +60,6 @@ int mainboard_smi_apmc(u8 apmc) return 0; } - intel_me_finalize_smm(); intel_pch_finalize_smm(); intel_northbridge_haswell_finalize_smm(); intel_cpu_haswell_finalize_smm(); diff --git a/src/southbridge/intel/lynxpoint/Kconfig b/src/southbridge/intel/lynxpoint/Kconfig index 3cf9ffe1e5..28ebdb6c2f 100644 --- a/src/southbridge/intel/lynxpoint/Kconfig +++ b/src/southbridge/intel/lynxpoint/Kconfig @@ -67,4 +67,13 @@ config IFD_BIN_PATH string "Path to intel firmware descriptor" default "3rdparty/mainboard/$(MAINBOARDDIR)/descriptor.bin" +config ME_MBP_CLEAR_LATE + bool "Defer wait for ME MBP Cleared" + default y + help + If you set this option to y, the Management Engine driver + will defer waiting for the MBP Cleared indicator until the + finalize step. This can speed up boot time if the ME takes + a long time to indicate this status. + endif diff --git a/src/southbridge/intel/lynxpoint/finalize.c b/src/southbridge/intel/lynxpoint/finalize.c index d81f90ecdb..e3f9cf0fd9 100644 --- a/src/southbridge/intel/lynxpoint/finalize.c +++ b/src/southbridge/intel/lynxpoint/finalize.c @@ -21,10 +21,14 @@ #include #include #include +#include "me.h" #include "pch.h" void intel_pch_finalize_smm(void) { + /* Lock down Management Engine */ + intel_me_finalize_smm(); + /* Set SPI opcode menu */ RCBA16(0x3894) = SPI_OPPREFIX; RCBA16(0x3896) = SPI_OPTYPE; diff --git a/src/southbridge/intel/lynxpoint/me_9.x.c b/src/southbridge/intel/lynxpoint/me_9.x.c index 01eb8447c6..5aa74f015d 100644 --- a/src/southbridge/intel/lynxpoint/me_9.x.c +++ b/src/southbridge/intel/lynxpoint/me_9.x.c @@ -62,6 +62,7 @@ static int intel_me_read_mbp(me_bios_payload *mbp_data, device_t dev); /* MMIO base address for MEI interface */ static u32 mei_base_address; +void intel_me_mbp_clear(device_t dev); #if CONFIG_DEBUG_INTEL_ME static void mei_dump(void *ptr, int dword, int offset, const char *type) @@ -116,14 +117,12 @@ static inline void mei_write_dword_ptr(void *ptr, int offset) mei_dump(ptr, dword, offset, "WRITE"); } -#ifndef __SMM__ static inline void pci_read_dword_ptr(device_t dev, void *ptr, int offset) { u32 dword = pci_read_config32(dev, offset); memcpy(ptr, &dword, sizeof(dword)); mei_dump(ptr, dword, offset, "PCI READ"); } -#endif static inline void read_host_csr(struct mei_csr *csr) { @@ -351,6 +350,47 @@ static inline int mei_sendrecv(struct mei_header *mei, struct mkhi_header *mkhi, return 0; } +/* + * mbp give up routine. This path is taken if hfs.mpb_rdy is 0 or the read + * state machine on the BIOS end doesn't match the ME's state machine. + */ +static void intel_me_mbp_give_up(device_t dev) +{ + struct mei_csr csr; + + pci_write_config32(dev, PCI_ME_H_GS2, PCI_ME_MBP_GIVE_UP); + + read_host_csr(&csr); + csr.reset = 1; + csr.interrupt_generate = 1; + write_host_csr(&csr); +} + +/* + * mbp clear routine. This will wait for the ME to indicate that + * the MBP has been read and cleared. + */ +void intel_me_mbp_clear(device_t dev) +{ + int count; + struct me_hfs2 hfs2; + + /* Wait for the mbp_cleared indicator */ + for (count = ME_RETRY; count > 0; --count) { + pci_read_dword_ptr(dev, &hfs2, PCI_ME_HFS2); + if (hfs2.mbp_cleared) + break; + udelay(ME_DELAY); + } + + if (count == 0) { + printk(BIOS_WARNING, "ME: Timeout waiting for mbp_cleared\n"); + intel_me_mbp_give_up(dev); + } else { + printk(BIOS_INFO, "ME: MBP cleared\n"); + } +} + #if (CONFIG_DEFAULT_CONSOLE_LOGLEVEL >= BIOS_DEBUG) && !defined(__SMM__) static inline void print_cap(const char *name, int state) { @@ -497,6 +537,11 @@ void intel_me_finalize_smm(void) if (!mei_base_address || mei_base_address == 0xfffffff0) return; +#if CONFIG_ME_MBP_CLEAR_LATE + /* Wait for ME MBP Cleared indicator */ + intel_me_mbp_clear(PCH_ME_DEV); +#endif + /* Make sure ME is in a mode that expects EOP */ reg32 = pci_read_config32(PCH_ME_DEV, PCI_ME_HFS); memcpy(&hfs, ®32, sizeof(u32)); @@ -798,23 +843,6 @@ static u32 host_to_me_words_room(void) } #endif -/* - * mbp give up routine. This path is taken if hfs.mpb_rdy is 0 or the read - * state machine on the BIOS end doesn't match the ME's state machine. - */ -static void intel_me_mbp_give_up(device_t dev) -{ - u32 reg32; - struct mei_csr csr; - - reg32 = PCI_ME_MBP_GIVE_UP; - pci_write_config32(dev, PCI_ME_H_GS2, reg32); - read_host_csr(&csr); - csr.reset = 1; - csr.interrupt_generate = 1; - write_host_csr(&csr); -} - struct mbp_payload { mbp_header header; u32 data[0]; @@ -830,7 +858,6 @@ static int intel_me_read_mbp(me_bios_payload *mbp_data, device_t dev) u32 me2host_pending; struct mei_csr host; struct me_hfs2 hfs2; - int count; struct mbp_payload *mbp; int i; @@ -876,18 +903,10 @@ static int intel_me_read_mbp(me_bios_payload *mbp_data, device_t dev) host.interrupt_generate = 1; write_host_csr(&host); +#if !CONFIG_ME_MBP_CLEAR_LATE /* Wait for the mbp_cleared indicator. */ - for (count = ME_RETRY; count > 0; --count) { - pci_read_dword_ptr(dev, &hfs2, PCI_ME_HFS2); - if (hfs2.mbp_cleared) - break; - udelay(ME_DELAY); - } - - if (count == 0) { - printk(BIOS_WARNING, "ME: Timeout waiting for mbp_cleared\n"); - intel_me_mbp_give_up(dev); - } + intel_me_mbp_clear(dev); +#endif /* Dump out the MBP contents. */ #if (CONFIG_DEFAULT_CONSOLE_LOGLEVEL >= BIOS_DEBUG)