[Skiboot] [PATCH 5/6] ast-io: Rework setup/tear-down of communication with the BMC
Andrew Jeffery
andrew at aj.id.au
Tue Jul 17 12:02:53 AEST 2018
It's possible for the platform to configure the BMC with SuperIO
access disabled. Rework the interfaces to report failures if SuperIO is
not enabled, and clean up once we're finished.
Signed-off-by: Andrew Jeffery <andrew at aj.id.au>
---
hw/ast-bmc/ast-io.c | 63 +++++++++++++++++-
include/ast.h | 19 ++++--
platforms/astbmc/astbmc.h | 1 +
platforms/astbmc/common.c | 114 +++++++++++++++++++++++++++------
platforms/astbmc/romulus.c | 2 +-
platforms/astbmc/witherspoon.c | 3 +-
platforms/qemu/qemu.c | 4 +-
7 files changed, 175 insertions(+), 31 deletions(-)
diff --git a/hw/ast-bmc/ast-io.c b/hw/ast-bmc/ast-io.c
index a55287168fe3..eb80181e481a 100644
--- a/hw/ast-bmc/ast-io.c
+++ b/hw/ast-bmc/ast-io.c
@@ -119,6 +119,17 @@
#define BMC_SIO_SCR29_MBOX 0x08
#define BMC_SIO_SCR29_MEMBOOT 0x10
+/*
+ * SIO Register 0x2d: Platform Flags (normal bit ordering)
+ *
+ * [ 7 ] Hostboot configures SUART
+ * [ 6 ] Hostboot configures VUART
+ * [5:1] Reserved
+ * [ 0 ] Isolate Service Processor
+ */
+#define BMC_SIO_PLAT_FLAGS 0x2d
+#define BMC_SIO_PLAT_ISOLATE_SP 0x01
+
enum {
BMC_SIO_DEV_NONE = -1,
BMC_SIO_DEV_UART1 = 2,
@@ -310,10 +321,58 @@ static void ast_setup_sio_irq_polarity(void)
bmc_sio_put(true);
}
-void ast_io_init(void)
+static bool ast_sio_is_enabled(void)
{
+ bool enabled;
+
+ lpc_outb(0xa5, 0x2e);
+ lpc_outb(0xa5, 0x2e);
+
+ /* Heuristic attempt to confirm SIO is enabled.
+ *
+ * Do two tests of 1 byte, giving a false positive probability of
+ * 1/65536. Read tests on disabled SIO tended to return 0x60.
+ */
+ bmc_sio_outb(0x2, 0x07);
+ enabled = bmc_sio_inb(0x07) == 2;
+ if (enabled) {
+ bmc_sio_outb(0xd, 0x07);
+ enabled = bmc_sio_inb(0x07) == 0xd;
+ }
+
+ if (enabled)
+ lpc_outb(0xaa, 0x2e);
+
+ return enabled;
+}
+
+bool ast_sio_init(void)
+{
+ bool enabled = ast_sio_is_enabled();
+
+ prlog(PR_NOTICE, "PLAT: SuperIO is %s\n",
+ enabled ? "available" : "unavailable!");
+
/* Configure all AIO interrupts to level low */
- ast_setup_sio_irq_polarity();
+ if (enabled)
+ ast_setup_sio_irq_polarity();
+
+ return enabled;
+}
+
+bool ast_can_isolate_sp(void)
+{
+ return bmc_sio_inb(BMC_SIO_PLAT_FLAGS) & BMC_SIO_PLAT_ISOLATE_SP;
+}
+
+bool ast_io_is_rw(void)
+{
+ return !(ast_ahb_readl(LPC_HICRB) & LPC_HICRB_ILPC_DISABLE);
+}
+
+bool ast_io_init(void)
+{
+ return ast_io_is_rw();
}
bool ast_lpc_fw_is_mbox(void)
diff --git a/include/ast.h b/include/ast.h
index 3525c828a217..1b5e0013542b 100644
--- a/include/ast.h
+++ b/include/ast.h
@@ -39,6 +39,8 @@
#define LPC_HICR6 (LPC_BASE + 0x80)
#define LPC_HICR7 (LPC_BASE + 0x88)
#define LPC_HICR8 (LPC_BASE + 0x8c)
+#define LPC_HICRB (LPC_BASE + 0x100)
+#define LPC_HICRB_ILPC_DISABLE (1 << 6)
#define LPC_iBTCR0 (LPC_BASE + 0x140)
/* VUART1 */
@@ -49,9 +51,15 @@
#define VUART1_ADDRH (VUART1_BASE + 0x2c)
/* SCU registers */
-#define SCU_BASE 0x1e6e2000
-#define SCU_HW_STRAPPING (SCU_BASE + 0x70)
-#define SCU_REVISION_ID (SCU_BASE + 0x7C)
+#define SCU_BASE 0x1e6e2000
+#define SCU_HW_STRAPPING (SCU_BASE + 0x70)
+#define SCU_STRAP_SIO_DECODE_DISABLE (1 << 20)
+#define SCU_REVISION_ID (SCU_BASE + 0x7C)
+#define SCU_REVISION_SOC_FAMILY(x) (((x) >> 24) & 0xff)
+#define SCU_REVISION_SOC_FAMILY_2400 0x02
+#define SCU_REVISION_SOC_FAMILY_2500 0x04
+#define SCU_REVISION_HW_REVISION_ID(x) (((x) >> 16) & 0xff)
+#define SCU_REVISION_CHIP_BONDING(x) (((x) >> 8) & 0x3)
/* MCR registers */
#define MCR_BASE 0x1e6e0000
@@ -73,7 +81,10 @@
void ast_ahb_writel(uint32_t val, uint32_t reg);
uint32_t ast_ahb_readl(uint32_t reg);
-void ast_io_init(void);
+bool ast_sio_init(void);
+bool ast_can_isolate_sp(void);
+bool ast_io_init(void);
+bool ast_io_is_rw(void);
bool ast_lpc_fw_is_flash(void);
bool ast_lpc_fw_is_mbox(void);
bool ast_scratch_reg_is_mbox(void);
diff --git a/platforms/astbmc/astbmc.h b/platforms/astbmc/astbmc.h
index fb6c68a2055f..fc53d1a10b1e 100644
--- a/platforms/astbmc/astbmc.h
+++ b/platforms/astbmc/astbmc.h
@@ -89,6 +89,7 @@ extern void astbmc_init(void);
extern void astbmc_ext_irq_serirq_cpld(unsigned int chip_id);
extern int pnor_init(void);
extern void check_all_slot_table(void);
+extern void astbmc_exit(void);
extern void slot_table_init(const struct slot_table_entry *top_table);
extern void slot_table_get_slot_info(struct phb *phb, struct pci_device * pd);
diff --git a/platforms/astbmc/common.c b/platforms/astbmc/common.c
index aa278a03849c..393ddbe7dd7e 100644
--- a/platforms/astbmc/common.c
+++ b/platforms/astbmc/common.c
@@ -381,6 +381,24 @@ static void astbmc_fixup_psi_bar(void)
xscom_write(chip->id, 0x201090A, psibar);
}
+static void astbmc_fixup_uart(void)
+{
+ /*
+ * Depending on which image we are running, it may be configuring the
+ * virtual UART or not. Check if VUART is enabled and use SIO if not.
+ * We also correct the configuration of VUART as some BMC images don't
+ * setup the interrupt properly
+ */
+ if (ast_is_vuart1_enabled()) {
+ printf("PLAT: Using virtual UART\n");
+ ast_disable_sio_uart1();
+ ast_setup_vuart1(UART_IO_BASE, UART_LPC_IRQ);
+ } else {
+ printf("PLAT: Using SuperIO UART\n");
+ ast_setup_sio_uart1(UART_IO_BASE, UART_LPC_IRQ);
+ }
+}
+
void astbmc_early_init(void)
{
/* Hostboot's device-tree isn't quite right yet */
@@ -392,28 +410,24 @@ void astbmc_early_init(void)
/* Send external interrupts to me */
psi_set_external_irq_policy(EXTERNAL_IRQ_POLICY_SKIBOOT);
- /* Initialize AHB accesses via AST2400 */
- ast_io_init();
+ if (ast_sio_init()) {
+ if (!ast_can_isolate_sp()) {
+ /*
+ * BMCs claiming support for isolation must have
+ * correctly configured the UART and BT for host
+ * firmware. If not, let's apply some fixups for broken
+ * BMC firmwares.
+ */
+ if (ast_io_init()) {
+ astbmc_fixup_uart();
+ ast_setup_ibt(BT_IO_BASE, BT_LPC_IRQ);
+ } else
+ prerror("PLAT: AST IO initialisation failed!\n");
+ }
- /*
- * Depending on which image we are running, it may be configuring
- * the virtual UART or not. Check if VUART is enabled and use
- * SIO if not. We also correct the configuration of VUART as some
- * BMC images don't setup the interrupt properly
- */
- if (ast_is_vuart1_enabled()) {
- printf("PLAT: Using virtual UART\n");
- ast_disable_sio_uart1();
- ast_setup_vuart1(UART_IO_BASE, UART_LPC_IRQ);
- } else {
- printf("PLAT: Using SuperIO UART\n");
- ast_setup_sio_uart1(UART_IO_BASE, UART_LPC_IRQ);
- }
-
- /* Similarly, some BMCs don't configure the BT interrupt properly */
- ast_setup_ibt(BT_IO_BASE, BT_LPC_IRQ);
-
- ast_setup_sio_mbox(MBOX_IO_BASE, MBOX_LPC_IRQ);
+ ast_setup_sio_mbox(MBOX_IO_BASE, MBOX_LPC_IRQ);
+ } else
+ prerror("PLAT: AST SIO initialisation failed!\n");
/* Setup UART and use it as console */
uart_init();
@@ -423,6 +437,64 @@ void astbmc_early_init(void)
prd_init();
}
+static bool astbmc_isolate_via_io(void)
+{
+ uint32_t hw_strapping;
+ uint32_t silicon_rev;
+ uint8_t family;
+
+ silicon_rev = ast_ahb_readl(SCU_REVISION_ID);
+ family = SCU_REVISION_SOC_FAMILY(silicon_rev);
+
+ if (family == SCU_REVISION_SOC_FAMILY_2400) {
+ /* Strapping is read-modify-write on SCU70 */
+ hw_strapping = SCU_STRAP_SIO_DECODE_DISABLE;
+ hw_strapping |= ast_ahb_readl(SCU_HW_STRAPPING);
+ } else if (family == SCU_REVISION_SOC_FAMILY_2500) {
+ /*
+ * Strapping is W1S on SCU70, W1C on SCU7C. We're setting a bit
+ * so read-modify-write *should* work, but in reality it breaks
+ * the AXI/AHB divider, so don't do that.
+ */
+ hw_strapping = SCU_STRAP_SIO_DECODE_DISABLE;
+ } else {
+ prerror("PLAT: Unrecognised BMC silicon revision 0x%x, isolation failed\n",
+ silicon_rev);
+ return false;
+ }
+
+ ast_ahb_writel(hw_strapping, SCU_HW_STRAPPING);
+
+ return true;
+}
+
+static bool astbmc_isolate_via_ipmi(void)
+{
+ return false;
+}
+
+static void astbmc_isolate(void)
+{
+ bool isolated;
+
+ isolated = ast_io_is_rw() ? astbmc_isolate_via_io()
+ : astbmc_isolate_via_ipmi();
+
+ if (!isolated) {
+ prlog(PR_EMERG, "PLAT: BMC isolation failed\n");
+ abort();
+ }
+
+ prlog(PR_INFO, "PLAT: Isolated BMC\n");
+}
+
+void astbmc_exit(void)
+{
+ if (ast_can_isolate_sp())
+ astbmc_isolate();
+ ipmi_wdt_final_reset();
+}
+
const struct bmc_platform astbmc_ami = {
.name = "AMI",
.ipmi_oem_partial_add_esel = IPMI_CODE(0x3a, 0xf0),
diff --git a/platforms/astbmc/romulus.c b/platforms/astbmc/romulus.c
index 8d3d10466b6c..67c594638b8d 100644
--- a/platforms/astbmc/romulus.c
+++ b/platforms/astbmc/romulus.c
@@ -80,6 +80,6 @@ DECLARE_PLATFORM(romulus) = {
.cec_power_down = astbmc_ipmi_power_down,
.cec_reboot = astbmc_ipmi_reboot,
.elog_commit = ipmi_elog_commit,
- .exit = ipmi_wdt_final_reset,
+ .exit = astbmc_exit,
.terminate = ipmi_terminate,
};
diff --git a/platforms/astbmc/witherspoon.c b/platforms/astbmc/witherspoon.c
index cb09eefe048c..d663709f8766 100644
--- a/platforms/astbmc/witherspoon.c
+++ b/platforms/astbmc/witherspoon.c
@@ -29,6 +29,7 @@
#include <phb4.h>
#include "astbmc.h"
+#include "ast.h"
/*
* HACK: Hostboot doesn't export the correct data for the system VPD EEPROM
@@ -165,7 +166,7 @@ DECLARE_PLATFORM(witherspoon) = {
.cec_power_down = astbmc_ipmi_power_down,
.cec_reboot = astbmc_ipmi_reboot,
.elog_commit = ipmi_elog_commit,
- .exit = ipmi_wdt_final_reset,
+ .exit = astbmc_exit,
.terminate = ipmi_terminate,
.pci_get_slot_info = dt_slot_get_slot_info,
diff --git a/platforms/qemu/qemu.c b/platforms/qemu/qemu.c
index dee61cce4c78..a9b4f57b57b4 100644
--- a/platforms/qemu/qemu.c
+++ b/platforms/qemu/qemu.c
@@ -246,8 +246,8 @@ static bool qemu_probe(void)
psi_set_external_irq_policy(EXTERNAL_IRQ_POLICY_SKIBOOT);
- /* Initialize AHB accesses via AST2400 */
- ast_io_init();
+ if (!ast_sio_init())
+ prerror("PLAT: AST SIO initialisation failed!\n");
/* Setup UART and use it as console */
uart_init();
--
2.17.1
More information about the Skiboot
mailing list