From 17ee7c1c6decadad5207bc641a25bf17e70267da Mon Sep 17 00:00:00 2001 From: spashabk-in Date: Tue, 28 Aug 2018 07:18:36 -0500 Subject: Enabling ipmi console access Implementation of virtual UART drivers over lpc for IPMI console logs from SBE Change-Id: Icfa4d9833780019eb59c34dc92830afda53eced0 Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/65348 Tested-by: Jenkins Server Tested-by: FSP CI Jenkins Reviewed-by: RAJA DAS Reviewed-by: Sachin Gupta --- src/sbefw/app/power/ipl_table.C | 21 +++- src/sbefw/core/corefiles.mk | 3 + src/sbefw/core/sbeConsole.C | 261 ++++++++++++++++++++++++++++++++++++++++ src/sbefw/core/sbeConsole.H | 149 +++++++++++++++++++++++ src/sbefw/core/sbe_sp_intf.H | 1 + src/sbefw/core/sbeglobals.C | 4 + src/sbefw/core/sbeglobals.H | 6 + src/sbefw/core/sbemain.C | 7 ++ 8 files changed, 451 insertions(+), 1 deletion(-) create mode 100644 src/sbefw/core/sbeConsole.C create mode 100644 src/sbefw/core/sbeConsole.H (limited to 'src/sbefw') diff --git a/src/sbefw/app/power/ipl_table.C b/src/sbefw/app/power/ipl_table.C index ca3298bf..86b41f41 100644 --- a/src/sbefw/app/power/ipl_table.C +++ b/src/sbefw/app/power/ipl_table.C @@ -109,6 +109,8 @@ #include "p9_fbc_utils.H" #include "sbeSecureMemRegionManager.H" +#include "sbeConsole.H" + // Forward declaration using namespace fapi2; @@ -176,6 +178,7 @@ using sbeIstepHwpCacheInitf_t = ReturnCode (*) // Forward declarations // Wrapper function which will call HWP. ReturnCode istepWithProc( voidfuncptr_t i_hwp ); +ReturnCode istepLpcInit( voidfuncptr_t i_hwp ); ReturnCode istepHwpTpSwitchGears( voidfuncptr_t i_hwp); ReturnCode istepAttrSetup( voidfuncptr_t i_hwp ); ReturnCode istepNoOp( voidfuncptr_t i_hwp ); @@ -301,7 +304,7 @@ static istepMap_t g_istep3PtrTbl[] = ISTEP_MAP( istepWithProc, p9_sbe_io_initf ), ISTEP_MAP( istepWithProc, p9_sbe_startclock_chiplets ), ISTEP_MAP( istepWithProc, p9_sbe_scominit ), - ISTEP_MAP( istepWithProc, p9_sbe_lpc_init ), + ISTEP_MAP( istepLpcInit, p9_sbe_lpc_init ), ISTEP_MAP( istepWithProc, p9_sbe_fabricinit ), ISTEP_MAP( istepCheckSbeMaster, NULL ), ISTEP_MAP( istepWithProc, p9_sbe_mcs_setup ), @@ -389,6 +392,19 @@ ReturnCode istepWithProc( voidfuncptr_t i_hwp) } //---------------------------------------------------------------------------- +ReturnCode istepLpcInit( voidfuncptr_t i_hwp) +{ + ReturnCode rc = FAPI2_RC_SUCCESS; + Target proc = plat_getChipTarget(); + assert( NULL != i_hwp ); + SBE_EXEC_HWP(rc, reinterpret_cast( i_hwp ), proc) + SBE_UART_INIT; + SBE_MSG_CONSOLE( SBE_CONSOLE_WELCOME_MSG ); + + return rc; +} +//---------------------------------------------------------------------------- + ReturnCode istepHwpTpSwitchGears( voidfuncptr_t i_hwp) { ReturnCode rc = FAPI2_RC_SUCCESS; @@ -643,6 +659,9 @@ ReturnCode istepLoadBootLoader( voidfuncptr_t i_hwp) ReturnCode istepStartInstruction( voidfuncptr_t i_hwp) { ReturnCode rc = FAPI2_RC_SUCCESS; + + SBE_MSG_CONSOLE("SBE starting hostboot"); + SBE_UART_DISABLE; rc = istepWithCore(i_hwp); if(rc == FAPI2_RC_SUCCESS) { diff --git a/src/sbefw/core/corefiles.mk b/src/sbefw/core/corefiles.mk index 3b3bf233..2b110523 100644 --- a/src/sbefw/core/corefiles.mk +++ b/src/sbefw/core/corefiles.mk @@ -58,6 +58,9 @@ CORESEEPROM-CPP-SOURCES = sbeSecureMemRegionManager.C ifeq ($(SBE_S0_SUPPORT), 1) CORESEEPROM-CPP-SOURCES += sbes0handler.C endif +ifeq ($(SBE_CONSOLE_SUPPORT), 1) +CORESEEPROM-CPP-SOURCES += sbeConsole.C +endif CORESEEPROM-C-SOURCES = CORESEEPROM-S-SOURCES = diff --git a/src/sbefw/core/sbeConsole.C b/src/sbefw/core/sbeConsole.C new file mode 100644 index 00000000..6f0db4ef --- /dev/null +++ b/src/sbefw/core/sbeConsole.C @@ -0,0 +1,261 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbeConsole.C $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2018 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +#include "sbetrace.H" +#include "fapi2.H" + +#include "sbeConsole.H" + +#include "p9_perv_scom_addresses.H" +#include "p9_perv_scom_addresses_fld.H" +#include "p9_misc_scom_addresses.H" +#include "p9_misc_scom_addresses_fld.H" + +#include "sberegaccess.H" +#include "sbeglobals.H" +#include "p9_lpc_utils.H" + +using namespace fapi2; + +static uint32_t writeReg(uint8_t i_addr, + uint8_t i_data) +{ + uint32_t rc = SBE_SEC_OPERATION_SUCCESSFUL; + + do { + Target proc = plat_getChipTarget(); + + buffer data = 0; + data.insert(i_data, 0, 8); + + ReturnCode fapiRc = lpc_rw(proc, + LPC_IO_SPACE + uartBase + i_addr, + sizeof(uint8_t), + false, + false, + data); + if(fapiRc != FAPI2_RC_SUCCESS) + { + rc = SBE_SEC_LPC_ACCESS_FAILED; + break; + } + } while(0); + + return rc; +} + +static uint32_t readReg(uint8_t i_addr, + uint8_t &o_data) +{ + uint32_t rc = SBE_SEC_OPERATION_SUCCESSFUL; + + do + { + Target proc = plat_getChipTarget(); + + buffer data = 0; + ReturnCode fapiRc = lpc_rw(proc, + LPC_IO_SPACE + uartBase + i_addr, + sizeof(uint8_t), + true, + false, + data); + if(fapiRc != FAPI2_RC_SUCCESS) + { + rc = SBE_SEC_LPC_ACCESS_FAILED; + break; + } + data.extract(o_data, 0, 8); + } while(0); + + return rc; +} + +void uartInit(void) +{ + #define SBE_FUNC "uartInit" + uint32_t rc = SBE_SEC_OPERATION_SUCCESSFUL; + + uint8_t lpcConsoleCfg = 0; + FAPI_ATTR_GET(fapi2::ATTR_LPC_CONSOLE_CNFG, + plat_getChipTarget(), + lpcConsoleCfg); + if(!lpcConsoleCfg) + { + SBE_INFO(SBE_FUNC " ATTR_LPC_CONSOLE_CNFG not set"); + return; + } + do { + // Check for existence of scratch register (and thus UART device). + rc = writeReg(SCR, 'h'); + if(rc != SBE_SEC_OPERATION_SUCCESSFUL) + { + SBE_ERROR(SBE_FUNC " failure to write scratch for uart detection"); + break; + } + uint8_t data = 0; + rc = readReg(SCR, data); + if(rc != SBE_SEC_OPERATION_SUCCESSFUL) + { + SBE_ERROR(SBE_FUNC " failure to read scratch for uart detection"); + break; + } + if(data != 'h') + { + SBE_ERROR(SBE_FUNC " uart device not found!"); + break; + } + + struct i2c_config { + uint8_t reg; + uint8_t data; + }; + + i2c_config configTable[] = { + {LSR, 0x00}, // clear line control register + {IER, 0x00}, // clear interrupt register + {LCR, LCR_DLAB}, // set baud rate + {DLL, uartDivisor & 0xff}, + {DLM, uartDivisor >> 8}, + {LCR, LCR_DWL8 | LCR_NOP | LCR_STP1}, // set 8N1 mode + {MCR, MCR_RTS | MCR_DTR}, // enable Request-to-send/Data-terminal-ready + {FCR, FCR_ENF | FCR_CLFR | FCR_CLFT}, // clear and enable FIFOs + }; + + uint8_t step = 0; + for(auto config:configTable) { + rc = writeReg(config.reg, config.data); + if(rc != SBE_SEC_OPERATION_SUCCESSFUL) + { + SBE_ERROR(SBE_FUNC " failure step [%d]", step); + return; + } + step++; + } + + SBE_INFO(SBE_FUNC " UART device initialized."); + SBE_GLOBAL->sbeUartActive = true; + } while(0); + + #undef SBE_FUNC +} + +static void uartPutChar(char c) +{ + #define SBE_FUNC "uartPutChar" + uint32_t rc = SBE_SEC_OPERATION_SUCCESSFUL; + do { + static const uint64_t DELAY_NS = 100; + static const uint64_t DELAY_LOOPS = 100000000; + + uint64_t loops = 0; + uint8_t data = 0; + do { + rc = readReg(LSR, data); + if(rc != SBE_SEC_OPERATION_SUCCESSFUL) + { + SBE_ERROR(SBE_FUNC " failure to read LSR"); + break; + } + if(data == LSR_BAD || (data & LSR_THRE)) + { + break; + } + delay(DELAY_NS, 1000000); + } while(++loops < DELAY_LOOPS); + + if(rc != SBE_SEC_OPERATION_SUCCESSFUL) + { + SBE_ERROR(SBE_FUNC " LSR read error."); + break; + } + if(data == LSR_BAD) + { + SBE_ERROR(SBE_FUNC " LSR_BAD data error."); + break; + } + if(loops >= DELAY_LOOPS) + { + SBE_ERROR(SBE_FUNC " FIFO timeout."); + break; + } + + rc = writeReg(THR, c); + if(rc != SBE_SEC_OPERATION_SUCCESSFUL) + { + SBE_ERROR(SBE_FUNC " failure to write THR"); + break; + } + + } while(0); + + #undef SBE_FUNC +} + +void uartDisable(void) +{ + SBE_INFO("uart disabled"); + SBE_GLOBAL->sbeUartActive = false; +} + +void uartLock(void) +{ + int rcPk = PK_OK; + rcPk = pk_semaphore_pend (&SBE_GLOBAL->sbeUartBinSem, PK_WAIT_FOREVER); + // PK API failure + if (rcPk != PK_OK) + { + SBE_ERROR(SBE_FUNC"pk_semaphore_pend failed, " + "rcPk=%d, SBE_GLOBAL->sbeUartBinSem.count=%d", + rcPk, SBE_GLOBAL->sbeUartBinSem.count); + pk_halt(); + } +} + +void uartUnLock(void) +{ + int rcPk = PK_OK; + rcPk = pk_semaphore_post(&SBE_GLOBAL->sbeUartBinSem); + // PK API failure + if (rcPk != PK_OK) + { + SBE_ERROR(SBE_FUNC"pk_semaphore_post failed, " + "rcPk=%d, SBE_GLOBAL->sbeUartBinSem.count=%d", + rcPk, SBE_GLOBAL->sbeUartBinSem.count); + pk_halt(); + } +} +void sbeMsgConsole(char const *msg) +{ + if(SBE_GLOBAL->sbeUartActive) + { + size_t c = 0; + while(msg[c] != '\0') + { + uartPutChar(msg[c++]); + } + } + else + SBE_DEBUG("uart is not active"); +} diff --git a/src/sbefw/core/sbeConsole.H b/src/sbefw/core/sbeConsole.H new file mode 100644 index 00000000..fe9b5734 --- /dev/null +++ b/src/sbefw/core/sbeConsole.H @@ -0,0 +1,149 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbeConsole.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2018 */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +#pragma once + +#include "sbe_sp_intf.H" +#include "sbe_build_info.H" + +#define VARG_COUNT_HELPER(_0, _1, _2, _3, _4, _5, _6, _7, N, ...) N +#define VARG_COUNT(...) VARG_COUNT_HELPER(, ##__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0) + +#define SBE_MSG_CONSOLE_1(msg) \ + SBE_UART_LOCK; \ + _SBE_MSG_CONSOLE(msg); \ + _SBE_MSG_CONSOLE("\n\r"); \ + SBE_UART_UNLOCK; +#define SBE_MSG_CONSOLE_2(msg1, msg2) \ + SBE_UART_LOCK; \ + _SBE_MSG_CONSOLE(msg1); \ + _SBE_MSG_CONSOLE(" "); \ + _SBE_MSG_CONSOLE(msg2); \ + _SBE_MSG_CONSOLE("\n\r"); \ + SBE_UART_UNLOCK; +#define SBE_MSG_CONSOLE_HELPER_CALL(count, ...) SBE_MSG_CONSOLE_ ## count(__VA_ARGS__) +#define SBE_MSG_CONSOLE_HELPER(count, ...) SBE_MSG_CONSOLE_HELPER_CALL(count, __VA_ARGS__) +#define SBE_MSG_CONSOLE(...) SBE_MSG_CONSOLE_HELPER(VARG_COUNT(__VA_ARGS__), __VA_ARGS__) + +#ifndef SBE_CONSOLE_SUPPORT + +#define SBE_UART_INIT +#define SBE_UART_DISABLE +#define SBE_UART_LOCK +#define SBE_UART_UNLOCK +#define _SBE_MSG_CONSOLE(msg) + +#else + +#define SBE_UART_INIT uartInit() +#define SBE_UART_DISABLE uartDisable() +#define SBE_UART_LOCK uartLock() +#define SBE_UART_UNLOCK uartUnLock() + +// SBE messages +#define SBE_CONSOLE_WELCOME_MSG ("\n\r--== Welcome to SBE - CommitId[" STRINGIFY(SBE_COMMIT_ID) "] ==--") + +#define _SBE_MSG_CONSOLE(msg) \ + sbeMsgConsole(msg) +#define LPC_IO_SPACE 0xD0010000 +#define LPC_MAX_IO_SPACE (64*1024) + +void uartInit(void); +void uartDisable(void); +void uartLock(void); +void uartUnLock(void); +void sbeMsgConsole(char const *msg); +// +/** UART Register Offsets */ +enum +{ + RBR = 0, ///< Recv Buffer + THR = 0, ///< Tran Holding + DLL = 0, ///< Divisor Latch LSB + IER = 1, ///< Interrupt Enable + DLM = 1, ///< Divisor Latch MSB + FCR = 2, ///< FIFO Control + IIR = 2, ///< Interrupt Identification + LCR = 3, ///< Line Control + MCR = 4, ///< Modem Control + LSR = 5, ///< Line Status + MSR = 6, ///< Modem Status + SCR = 7, ///< Scratch +}; + +/** Line Status Register (LSR) bit definitions */ +enum +{ + LSR_DR = 0x01, ///< Data ready + LSR_OE = 0x02, ///< Overrun + LSR_PE = 0x04, ///< Parity error + LSR_FE = 0x08, ///< Framing error + LSR_BI = 0x10, ///< Break + LSR_THRE = 0x20, ///< Xmit holding register empty + LSR_TEMT = 0x40, ///< Xmitter empty + LSR_ERR = 0x80, ///< Error + LSR_BAD = 0xff, ///< Invalid value for LSR +}; + +/** Line Control Register (LCR) bit definitions */ +enum +{ + LCR_DWL5 = 0x00, ///< Data word length: 5 bits + LCR_DWL6 = 0x01, ///< Data word length: 6 bits + LCR_DWL7 = 0x02, ///< Data word length: 7 bits + LCR_DWL8 = 0x03, ///< Data word length: 8 bits + + LCR_STP1 = 0x00, ///< 1 stop bits + LCR_STP2 = 0x04, ///< 1.5(5) or 2(6,7,8) stop bits + + LCR_NOP = 0x00, ///< No Parity + LCR_ODDP = 0x08, ///< Odd Parity + LCR_EVEP = 0x18, ///< Even Parity + LCR_HIP = 0x28, ///< High Parity + LCR_LOP = 0x38, ///< Low Parity + + LCR_DLAB = 0x80, ///< DLL access +}; + +/** Modem Control Register (MCR) bit definitions */ +enum +{ + MCR_DTR = 0x01, ///< Data terminal ready + MCR_RTS = 0x02, ///< Request to send +}; + +/** FIFO Control Register (FCR) bit definitions */ +enum +{ + FCR_ENF = 0x01, ///< Enable FIFOs. + FCR_CLFR = 0x02, ///< Clear Receive FIFO. + FCR_CLFT = 0x04, ///< Clear Transmit FIFO +}; + +// uart config +static const uint64_t uartBase = 0x3f8; +static const uint64_t uartBaud = 115200; +static const uint64_t uartClock = 1843200; +static const uint64_t uartDivisor = ((uartClock / 16) / uartBaud); + +#endif // SBE_CONSOLE_SUPPORT diff --git a/src/sbefw/core/sbe_sp_intf.H b/src/sbefw/core/sbe_sp_intf.H index f238a80a..678ab626 100644 --- a/src/sbefw/core/sbe_sp_intf.H +++ b/src/sbefw/core/sbe_sp_intf.H @@ -229,6 +229,7 @@ enum sbeSecondaryResponse SBE_SEC_SPECIAL_WAKEUP_TIMEOUT = 0x28, SBE_SEC_SPECIAL_WAKEUP_SCOM_FAILURE = 0x29, SBE_SEC_S0_ARCH_REG_DUMP_FAILED = 0x2A, + SBE_SEC_LPC_ACCESS_FAILED = 0x2B, }; /** diff --git a/src/sbefw/core/sbeglobals.C b/src/sbefw/core/sbeglobals.C index c5f898b9..d4640107 100644 --- a/src/sbefw/core/sbeglobals.C +++ b/src/sbefw/core/sbeglobals.C @@ -55,3 +55,7 @@ uint8_t SBEGlobalsSingleton::failedCmdClass = 0; uint8_t SBEGlobalsSingleton::failedCmd = 0; bool SBEGlobalsSingleton::isHreset = false; + +#ifdef SBE_CONSOLE_SUPPORT +bool SBEGlobalsSingleton::sbeUartActive = false; +#endif diff --git a/src/sbefw/core/sbeglobals.H b/src/sbefw/core/sbeglobals.H index e7bd76b6..3b2b0ad9 100644 --- a/src/sbefw/core/sbeglobals.H +++ b/src/sbefw/core/sbeglobals.H @@ -85,6 +85,12 @@ class SBEGlobalsSingleton */ PkSemaphore sbeSemAsyncProcess; + #ifdef SBE_CONSOLE_SUPPORT + // Binary semaphore to protect uart access + PkSemaphore sbeUartBinSem; + static bool sbeUartActive; + #endif + sbeRole SBERole; // SBE Frequency. Initially nest frequency is 133 MHZ uint32_t sbefreq; diff --git a/src/sbefw/core/sbemain.C b/src/sbefw/core/sbemain.C index 9bcc53e0..9fbaf6bc 100644 --- a/src/sbefw/core/sbemain.C +++ b/src/sbefw/core/sbemain.C @@ -128,6 +128,13 @@ uint32_t sbeInitSems(void) { break; } + #ifdef SBE_CONSOLE_SUPPORT + l_rc = pk_semaphore_create(&SBE_GLOBAL->sbeUartBinSem, 1, 1); + if (l_rc) + { + break; + } + #endif } while (false); if (l_rc) -- cgit v1.2.1