Johnny Lin has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/40234 )
Change subject: drivers/ipmi: Add IPMI KCS support in romstage ......................................................................
drivers/ipmi: Add IPMI KCS support in romstage
It's necessary to run IPMI commands in romstage for writing error SEL such as memory initialization error SEL, and also for other usages such as starting FRB2 timer, OEM commands, etc.
Change-Id: Ie3198965670454b123e570f9056673fdf515f52b Signed-off-by: Johnny Lin johnny_lin@wiwynn.com --- M src/drivers/ipmi/Kconfig M src/drivers/ipmi/Makefile.inc M src/drivers/ipmi/ipmi_kcs.h A src/drivers/ipmi/ipmi_kcs_ops_premem.c 4 files changed, 129 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/34/40234/1
diff --git a/src/drivers/ipmi/Kconfig b/src/drivers/ipmi/Kconfig index 37cfc0d..0304cb0 100644 --- a/src/drivers/ipmi/Kconfig +++ b/src/drivers/ipmi/Kconfig @@ -18,3 +18,10 @@ IPMB messages are limited to 32-bytes total. When the data size is larger than this value, IPMI can complete reading/writing the data over multiple commands. + +config IPMI_KCS_ROMSTAGE + bool + default n + depends on IPMI_KCS + help + IPMI KCS support in romstage. diff --git a/src/drivers/ipmi/Makefile.inc b/src/drivers/ipmi/Makefile.inc index 973fff8..06a3433 100644 --- a/src/drivers/ipmi/Makefile.inc +++ b/src/drivers/ipmi/Makefile.inc @@ -2,3 +2,6 @@ ramstage-$(CONFIG_IPMI_KCS) += ipmi_kcs_ops.c ramstage-$(CONFIG_IPMI_KCS) += ipmi_ops.c ramstage-$(CONFIG_IPMI_KCS) += ipmi_fru.c +romstage-$(CONFIG_IPMI_KCS_ROMSTAGE) += ipmi_kcs_ops_premem.c +romstage-$(CONFIG_IPMI_KCS_ROMSTAGE) += ipmi_kcs.c +romstage-$(CONFIG_IPMI_KCS_ROMSTAGE) += ipmi_ops.c diff --git a/src/drivers/ipmi/ipmi_kcs.h b/src/drivers/ipmi/ipmi_kcs.h index 9a04377..5de77ed 100644 --- a/src/drivers/ipmi/ipmi_kcs.h +++ b/src/drivers/ipmi/ipmi_kcs.h @@ -40,6 +40,9 @@ const unsigned char *inmsg, int inlen, unsigned char *outmsg, int outlen);
+/* Run basic IPMI init functions in romstage from the provided PnP device */ +void ipmi_kcs_premem_init(const u16 port, const u16 device); + struct ipmi_rsp { uint8_t lun; uint8_t cmd; diff --git a/src/drivers/ipmi/ipmi_kcs_ops_premem.c b/src/drivers/ipmi/ipmi_kcs_ops_premem.c new file mode 100644 index 0000000..e601041 --- /dev/null +++ b/src/drivers/ipmi/ipmi_kcs_ops_premem.c @@ -0,0 +1,116 @@ +/* + * This file is part of the coreboot project. + * + * 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 <console/console.h> + +#include <device/pnp.h> +#include <delay.h> +#include <timer.h> +#include "ipmi_kcs.h" +#include "chip.h" + +static int ipmi_get_bmc_self_test_result(const struct device *dev, + struct ipmi_selftest_rsp *rsp) +{ + int ret; + + ret = ipmi_kcs_message(dev->path.pnp.port, IPMI_NETFN_APPLICATION, 0, + IPMI_BMC_GET_SELFTEST_RESULTS, NULL, 0, (u8 *)rsp, + sizeof(*rsp)); + + if (ret < sizeof(struct ipmi_rsp) || rsp->resp.completion_code) { + printk(BIOS_ERR, "IPMI: %s command failed (ret=%d resp=0x%x)\n", + __func__, ret, rsp->resp.completion_code); + return 1; + } + if (ret != sizeof(*rsp)) { + printk(BIOS_ERR, "IPMI: %s response truncated\n", __func__); + return 1; + } + + return 0; +} + +void ipmi_kcs_premem_init(const u16 port, const u16 device) +{ + const struct drivers_ipmi_config *conf = NULL; + struct ipmi_selftest_rsp selftestrsp; + uint8_t retry_count; + const struct device *dev; + + /* Find IPMI pnp device from devicetree in romstage */ + dev = dev_find_slot_pnp(port, device); + + if (!dev) { + printk(BIOS_ERR, "IPMI: Cannot find pnp device port: %x, device %x\n", + port, device); + return; + } + if (!dev->enabled) + return; + + printk(BIOS_DEBUG, "IPMI: romstage PNP KCS 0x%x\n", dev->path.pnp.port); + if (dev->chip_info) + conf = dev->chip_info; + + if (conf && conf->wait_for_bmc && conf->bmc_boot_timeout) { + struct stopwatch sw; + stopwatch_init_msecs_expire(&sw, conf->bmc_boot_timeout * 1000); + printk(BIOS_INFO, "IPMI: Waiting for BMC...\n"); + + while (!stopwatch_expired(&sw)) { + if (inb(dev->path.pnp.port) != 0xff) + break; + mdelay(100); + } + if (stopwatch_expired(&sw)) { + printk(BIOS_INFO, "IPMI: Waiting for BMC timed out\n"); + return; + } + } + + printk(BIOS_INFO, "Get BMC self test result..."); + for (retry_count = 0; retry_count < conf->bmc_boot_timeout; retry_count++) { + if (!ipmi_get_bmc_self_test_result(dev, &selftestrsp)) + break; + + mdelay(1000); + } + + switch (selftestrsp.result) { + case IPMI_APP_SELFTEST_NO_ERROR: /* 0x55 */ + printk(BIOS_DEBUG, "No Error\n"); + break; + case IPMI_APP_SELFTEST_NOT_IMPLEMENTED: /* 0x56 */ + printk(BIOS_DEBUG, "Function Not Implemented\n"); + break; + case IPMI_APP_SELFTEST_ERROR: /* 0x57 */ + printk(BIOS_ERR, "BMC: Corrupted or inaccessible data or device\n"); + /* Don't write tables if communication failed */ + break; + case IPMI_APP_SELFTEST_FATAL_HW_ERROR: /* 0x58 */ + printk(BIOS_ERR, "BMC: Fatal Hardware Error\n"); + /* Don't write tables if communication failed */ + break; + case IPMI_APP_SELFTEST_RESERVED: /* 0xFF */ + printk(BIOS_DEBUG, "Reserved\n"); + break; + + default: /* Other Device Specific Hardware Error */ + printk(BIOS_ERR, "BMC: Device Specific Error\n"); + /* Don't write tables if communication failed */ + break; + } + +}