diff options
author | Brian Horton <brianh@linux.ibm.com> | 2015-02-11 17:25:44 -0600 |
---|---|---|
committer | A. Patrick Williams III <iawillia@us.ibm.com> | 2015-02-23 13:34:44 -0600 |
commit | 07bb80e9281ed8aafbd283d5ab2c0f777e347b73 (patch) | |
tree | b5970f8cc38dbddf3af745b2f492ff2f0e983a68 /src | |
parent | a6fa07dacc102c62067e20f69a4c956ac6d1f625 (diff) | |
download | talos-hostboot-07bb80e9281ed8aafbd283d5ab2c0f777e347b73.tar.gz talos-hostboot-07bb80e9281ed8aafbd283d5ab2c0f777e347b73.zip |
enable IPMI interface for hostboot runtime (hbrt)
This will be used by the errlog code to send committed
logs to the BMC, and by sensor code for read and writes.
Change-Id: Ie1f8013dddea99af14bfe166d45e7a74f0806efe
RTC: 120094
Reviewed-on: http://gfw160.aus.stglabs.ibm.com:8080/gerrit/15674
Tested-by: Jenkins Server
Reviewed-by: Brian Silver <bsilver@us.ibm.com>
Reviewed-by: STEPHEN M. CPREK <smcprek@us.ibm.com>
Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/include/runtime/interface.h | 98 | ||||
-rw-r--r-- | src/include/usr/ipmi/ipmi_reasoncodes.H | 1 | ||||
-rw-r--r-- | src/include/usr/ipmi/ipmisel.H | 35 | ||||
-rw-r--r-- | src/makefile | 2 | ||||
-rw-r--r-- | src/usr/ipmi/ipmirp.C | 2 | ||||
-rw-r--r-- | src/usr/ipmi/ipmisel.C | 277 | ||||
-rw-r--r-- | src/usr/ipmi/makefile | 1 | ||||
-rw-r--r-- | src/usr/ipmi/runtime/makefile | 37 | ||||
-rw-r--r-- | src/usr/ipmi/runtime/rt_ipmirp.C | 142 | ||||
-rw-r--r-- | src/usr/ipmi/runtime/test/makefile | 31 | ||||
-rw-r--r-- | src/usr/ipmi/runtime/test/rt_ipmitest.H | 102 | ||||
-rw-r--r-- | src/usr/testcore/rtloader/loader.H | 29 |
12 files changed, 606 insertions, 151 deletions
diff --git a/src/include/runtime/interface.h b/src/include/runtime/interface.h index 9ade9a07d..5279cb892 100644 --- a/src/include/runtime/interface.h +++ b/src/include/runtime/interface.h @@ -42,8 +42,29 @@ #include <stdint.h> #include <time.h> +/** Memory error types defined for memory_error() interface. */ +enum MemoryError_t +{ + /** Hardware has reported a solid memory CE that is correctable, but + * continues to report errors on subsequent reads. A second CE on that + * cache line will result in memory UE. Therefore, it is advised to migrate + * off of the address range as soon as possible. */ + MEMORY_ERROR_CE, + + /** Hardware has reported an uncorrectable error in memory (memory UE, + * channel failure, etc). The hypervisor should migrate any partitions off + * this address range as soon as possible. Note that these kind of errors + * will most likely result in partition failures. It is advised that the + * hypervisor waits some time for PRD to handle hardware attentions so that + * the hypervisor will know all areas of memory that are impacted by the + * failure. */ + MEMORY_ERROR_UE, +}; + + + /** - * i2c master description: chip, engine and port packed into + * I2C Master Description: chip, engine and port packed into * a single 64-bit argument * * --------------------------------------------------- @@ -51,12 +72,12 @@ * | (32) | (16) | (8) | (8) | * --------------------------------------------------- */ -#define HBRT_I2C_MASTER_CHIP_SHIFT 32 -#define HBRT_I2C_MASTER_CHIP_MASK (0xfffffffful << 32) -#define HBRT_I2C_MASTER_ENGINE_SHIFT 8 -#define HBRT_I2C_MASTER_ENGINE_MASK (0xfful << 8) -#define HBRT_I2C_MASTER_PORT_SHIFT 0 -#define HBRT_I2C_MASTER_PORT_MASK (0xfful) +#define HBRT_I2C_MASTER_CHIP_SHIFT 32 +#define HBRT_I2C_MASTER_CHIP_MASK (0xfffffffful << 32) +#define HBRT_I2C_MASTER_ENGINE_SHIFT 8 +#define HBRT_I2C_MASTER_ENGINE_MASK (0xfful << 8) +#define HBRT_I2C_MASTER_PORT_SHIFT 0 +#define HBRT_I2C_MASTER_PORT_MASK (0xfful) /** @typedef hostInterfaces_t @@ -154,9 +175,10 @@ typedef struct hostInterfaces void (*nanosleep)(uint64_t i_seconds, uint64_t i_nano_seconds); /** - * @brief Report an error to the host + * @brief Report an OCC error to the host * @param[in] Failing status that identifies the nature of the fail * @param[in] Identifier that specifies the failing part + * @platform FSP */ void (*report_failure)( uint64_t i_status, uint64_t i_partId ); @@ -197,15 +219,21 @@ typedef struct hostInterfaces int (*pnor_write) (uint32_t i_proc, const char* i_partitionName, uint64_t i_offset, void* i_data, size_t i_sizeBytes); + /** * @brief Read data from an i2c device - * @param[in] i_master - Chip/engine/port of i2c bus + * @param[in] i_master - chip, engine and port packed into + * a single 64-bit argument + * --------------------------------------------------- + * | chip | reserved | eng | port | + * | (32) | (16) | (8) | (8) | + * --------------------------------------------------- * @param[in] i_devAddr - I2C address of device * @param[in] i_offsetSize - Length of offset (in bytes) * @param[in] i_offset - Offset within device to read * @param[in] i_length - Number of bytes to read * @param[out] o_data - Data that was read - * @return 0 on success else return code + * @return 0 on success else return code * @platform OpenPOWER */ int (*i2c_read)( uint64_t i_master, uint16_t i_devAddr, @@ -214,7 +242,12 @@ typedef struct hostInterfaces /** * @brief Write data to an i2c device - * @param[in] i_master - Chip/engine/port of i2c bus + * @param[in] i_master - chip, engine and port packed into + * a single 64-bit argument + * --------------------------------------------------- + * | chip | reserved | eng | port | + * | (32) | (16) | (8) | (8) | + * --------------------------------------------------- * @param[in] i_devAddr - I2C address of device * @param[in] i_offsetSize - Length of offset (in bytes) * @param[in] i_offset - Offset within device to write @@ -227,7 +260,50 @@ typedef struct hostInterfaces uint32_t i_offsetSize, uint32_t i_offset, uint32_t i_length, void* i_data ); + /** + * @brief Perform an IPMI transaction + * @param[in] netfn The IPMI netfn byte + * @param[in] cmd The IPMI cmd byte + * @param[in] tx_buf The IPMI packet to send to the host + * @param[in] tx_size The number of bytes to send + * @param[in] rx_buf A buffer to be populated with the IPMI + * response. First bytes will be the + * IPMI completion code. + * @param[inout] rx_size The allocated size of the rx buffer on input + * updated to the size of the response on output. + * @retval rc - non-zero on error + * @platform OpenPower + */ + int (*ipmi_msg)(uint8_t netfn, uint8_t cmd, + void *tx_buf, size_t tx_size, + void *rx_buf, size_t *rx_size); + + + /** + * @brief Hardware has reported a memory error. This function requests the + * hypervisor to remove the all addresses within the address range given + * (including endpoints) from the available memory space. + * + * It is understood that the hypervisor may not be able to immediately + * deallocate the memory because it may be in use by a partition. Therefore, the + * hypervisor should cache all requests and deallocate the memory once it has + * been freed. + * + * @param i_startAddr The beginning address of the range. + * @param i_endAddr The end address of the range. + * @param i_errorType See enum MemoryError_t. + * + * @return 0 if the request is successfully received. Any value other than 0 on + * failure. The hypervisor should cache the request and return + * immediately. It should not wait for the request to be applied. See + * note above. + */ + int32_t memory_error( uint64_t i_startAddr, uint64_t i_endAddr, + MemoryError_t i_errorType ); + + // Reserve some space for future growth. + // do NOT ever change this number, even if you add functions. void (*reserved[32])(void); } hostInterfaces_t; diff --git a/src/include/usr/ipmi/ipmi_reasoncodes.H b/src/include/usr/ipmi/ipmi_reasoncodes.H index 6244b2d00..8040f934b 100644 --- a/src/include/usr/ipmi/ipmi_reasoncodes.H +++ b/src/include/usr/ipmi/ipmi_reasoncodes.H @@ -35,6 +35,7 @@ namespace IPMI MOD_IPMISRV_REPLY = 0x02, // IPMI::respond MOD_IPMISENSOR = 0x03, // IPMI::sensor MOD_IPMIDCMI = 0x04, // IPMI::sensor + MOD_IPMIRT = 0x05, // rt IPMI::send/IPMI::sendrecv }; enum IPMIReasonCode diff --git a/src/include/usr/ipmi/ipmisel.H b/src/include/usr/ipmi/ipmisel.H index 82d86bf6f..de2dd3218 100644 --- a/src/include/usr/ipmi/ipmisel.H +++ b/src/include/usr/ipmi/ipmisel.H @@ -202,8 +202,26 @@ namespace IPMISEL delete eSelExtra; } }; + + /** + * @brief parse the msg and call send_esel to send the esel (handles if + * the SEL reservation is lost) + * @param[in] i_msg + */ + void process_esel(msg_t *i_msg); + + /** + * @brief do the actual ipmi calls to send the esel data to the bmc + * @param[in] i_data esel data + * @param[in] o_err any error generated during the send + * @param[in] o_cc ipmi completion code from last sendrecv + */ + void send_esel(IPMISEL::eselInitData * i_data, + errlHndl_t &o_err, IPMI::completion_code &o_cc); + } // namespace IPMISEL +#ifndef __HOSTBOOT_RUNTIME class IpmiSEL { public: @@ -238,27 +256,12 @@ class IpmiSEL */ void execute(void); - /** - * @brief parse the msg and call send_esel to send the esel (handles if - * the SEL reservation is lost) - * @param[in] i_msg - */ - void process_esel(msg_t *i_msg) const; - - /** - * @brief do the actual ipmi calls to send the esel data to the bmc - * @param[in] i_data esel data - * @param[in] o_err any error generated during the send - * @param[in] o_cc ipmi completion code from last sendrecv - */ - void send_esel(IPMISEL::eselInitData * i_data, - errlHndl_t &o_err, IPMI::completion_code &o_cc) const; - msg_q_t iv_msgQ; //!< ipmi message queue //Disallow copying of this class. IpmiSEL& operator=(const IpmiSEL&); IpmiSEL(const IpmiSEL&); }; +#endif #endif diff --git a/src/makefile b/src/makefile index 97dbc3e39..6fdb8c6e6 100644 --- a/src/makefile +++ b/src/makefile @@ -236,6 +236,7 @@ RUNTIME_MODULES += $(if $(CONFIG_HTMGT),htmgt_rt) RUNTIME_MODULES += $(if $(CONFIG_HBRT_PRD),bus_training_rt) RUNTIME_MODULES += $(if $(CONFIG_HBRT_PRD),attn_rt) RUNTIME_MODULES += $(if $(CONFIG_HBRT_PRD),prdf_rt) +RUNTIME_MODULES += $(if $(CONFIG_BMC_IPMI),ipmi_rt) RUNTIME_MODULES += pnor_rt RUNTIME_DATA_MODULES += @@ -251,6 +252,7 @@ RUNTIME_TESTCASE_MODULES += testvpd_rt RUNTIME_TESTCASE_MODULES += testhwpf_rt RUNTIME_TESTCASE_MODULES += $(if $(CONFIG_HBRT_PRD),testprdf_rt) RUNTIME_TESTCASE_MODULES += $(if $(CONFIG_HBRT_PRD),testattn_rt) +RUNTIME_TESTCASE_MODULES += $(if $(CONFIG_BMC_IPMI),testipmi_rt) RUNTIME_TESTCASE_MODULES += testpnor_rt RELOCATABLE_IMAGE_LDFLAGS = -pie --export-dynamic diff --git a/src/usr/ipmi/ipmirp.C b/src/usr/ipmi/ipmirp.C index 51b943ab0..50f8ef2b5 100644 --- a/src/usr/ipmi/ipmirp.C +++ b/src/usr/ipmi/ipmirp.C @@ -865,7 +865,7 @@ namespace IPMI IPMI_TRAC("queuing sync %x:%x", ipmi_msg->iv_netfun, ipmi_msg->iv_cmd); int rc = msg_sendrecv(mq, ipmi_msg->iv_msg); - // If the kernel didn't give a hassle about he message, check to see if + // If the kernel didn't give a hassle about the message, check to see if // there was an error reported back from the other end of the queue. If // this message made it to the other end of the queue, then our memory // (io_data) is in the proper state. diff --git a/src/usr/ipmi/ipmisel.C b/src/usr/ipmi/ipmisel.C index df746f011..92a70faa5 100644 --- a/src/usr/ipmi/ipmisel.C +++ b/src/usr/ipmi/ipmisel.C @@ -44,125 +44,7 @@ extern trace_desc_t * g_trac_ipmi; #define IPMI_TRAC(printf_string,args...) \ TRACFCOMP(g_trac_ipmi,"sel: "printf_string,##args) -namespace IPMISEL -{ - void sendESEL(uint8_t* i_eselData, uint32_t i_dataSize, - uint32_t i_eid, uint8_t i_eventDirType, - uint8_t i_sensorType, uint8_t i_sensorNumber) - { - IPMI_TRAC(ENTER_MRK "sendESEL()"); - - // one message queue to the SEL thread - static msg_q_t mq = Singleton<IpmiSEL>::instance().msgQueue(); - - msg_t *msg = msg_allocate(); - msg->type = MSG_SEND_ESEL; - msg->data[0] = i_eid; - - // create the sel record of information - IPMISEL::selRecord l_sel; - l_sel.record_type = IPMISEL::record_type_ami_esel; - l_sel.generator_id = IPMISEL::generator_id_ami; - l_sel.evm_format_version = IPMISEL::format_ipmi_version_2_0; - l_sel.sensor_type = i_sensorType; - l_sel.sensor_number = i_sensorNumber; - l_sel.event_dir_type = i_eventDirType; - l_sel.event_data1 = IPMISEL::event_data1_ami; - - eselInitData *eselData = - new eselInitData(&l_sel, i_eselData, i_dataSize); - - msg->extra_data = eselData; - - //Send the msg to the sel thread - int rc = msg_send(mq,msg); - if(rc) - { - IPMI_TRAC(ERR_MRK "Failed (rc=%d) to send message",rc); - delete eselData; - } - IPMI_TRAC(EXIT_MRK "sendESEL"); - return; - } // sendESEL -} // IPMISEL - - -/** - * @brief Constructor - */ -IpmiSEL::IpmiSEL(void): - iv_msgQ(msg_q_create()) -{ - IPMI_TRAC(ENTER_MRK "IpmiSEL ctor"); - task_create(&IpmiSEL::start,NULL); -} - -/** - * @brief Destructor - */ -IpmiSEL::~IpmiSEL(void) -{ - msg_q_destroy(iv_msgQ); -} - -void* IpmiSEL::start(void* unused) -{ - Singleton<IpmiSEL>::instance().execute(); - return NULL; -} - -/** - * @brief Entry point of the sel ipmi thread - */ -//@todo: RTC 119832 -void IpmiSEL::execute(void) -{ - //Mark as an independent daemon so if it crashes we terminate. - task_detach(); - - // Register shutdown events with init service. - // Done at the "end" of shutdown processesing. - // This will flush out any IPMI messages which were sent as - // part of the shutdown processing. We chose MBOX priority - // as we don't want to accidentally get this message after - // interrupt processing has stopped in case we need intr to - // finish flushing the pipe. - INITSERVICE::registerShutdownEvent(iv_msgQ, IPMISEL::MSG_STATE_SHUTDOWN, - INITSERVICE::MBOX_PRIORITY); - - while(true) - { - msg_t* msg = msg_wait(iv_msgQ); - - const IPMISEL::msg_type msg_type = - static_cast<IPMISEL::msg_type>(msg->type); - - // Invert the "default" by checking here. This allows the compiler - // to warn us if the enum has an unhadled case but still catch - // runtime errors where msg_type is set out of bounds. - assert(msg_type <= IPMISEL::MSG_LAST_TYPE, - "msg_type %d not handled", msg_type); - - switch(msg_type) - { - case IPMISEL::MSG_SEND_ESEL: - process_esel(msg); - //done with msg - msg_free(msg); - break; - - case IPMISEL::MSG_STATE_SHUTDOWN: - IPMI_TRAC(INFO_MRK "ipmisel shutdown event"); - - //Respond that we are done shutting down. - msg_respond(iv_msgQ, msg); - break; - } - } // while(1) - IPMI_TRAC(EXIT_MRK "message loop"); - return; -} // execute - +// local functions /* * @brief Store either Record/Reserve ID from given data */ @@ -196,10 +78,63 @@ enum esel_retry SLEEP_BASE = 2 * NS_PER_MSEC, }; + +namespace IPMISEL +{ +void sendESEL(uint8_t* i_eselData, uint32_t i_dataSize, + uint32_t i_eid, uint8_t i_eventDirType, + uint8_t i_sensorType, uint8_t i_sensorNumber) +{ + IPMI_TRAC(ENTER_MRK "sendESEL()"); + +#ifdef __HOSTBOOT_RUNTIME + // HBRT doesn't send a msg, but use the msg structure to pass the data + msg_t l_msg; + msg_t *msg = &l_msg; + memset(msg, 0, sizeof(msg_t)); +#else + msg_t *msg = msg_allocate(); +#endif + msg->type = MSG_SEND_ESEL; + msg->data[0] = i_eid; + + // create the sel record of information + IPMISEL::selRecord l_sel; + l_sel.record_type = IPMISEL::record_type_ami_esel; + l_sel.generator_id = IPMISEL::generator_id_ami; + l_sel.evm_format_version = IPMISEL::format_ipmi_version_2_0; + l_sel.sensor_type = i_sensorType; + l_sel.sensor_number = i_sensorNumber; + l_sel.event_dir_type = i_eventDirType; + l_sel.event_data1 = IPMISEL::event_data1_ami; + + eselInitData *eselData = + new eselInitData(&l_sel, i_eselData, i_dataSize); + + msg->extra_data = eselData; + +#ifdef __HOSTBOOT_RUNTIME + process_esel(msg); +#else + // one message queue to the SEL thread + static msg_q_t mq = Singleton<IpmiSEL>::instance().msgQueue(); + + //Send the msg to the sel thread + int rc = msg_send(mq,msg); + if(rc) + { + IPMI_TRAC(ERR_MRK "Failed (rc=%d) to send message",rc); + delete eselData; + } +#endif + IPMI_TRAC(EXIT_MRK "sendESEL"); + return; +} // sendESEL + /* * @brief process esel msg */ -void IpmiSEL::process_esel(msg_t *i_msg) const +void process_esel(msg_t *i_msg) { errlHndl_t l_err = NULL; IPMI::completion_code l_cc = IPMI::CC_UNKBAD; @@ -212,7 +147,7 @@ void IpmiSEL::process_esel(msg_t *i_msg) const while (l_send_count > 0) { // try to send the eles to the bmc - send_esel(l_data, l_err, l_cc); + IPMISEL::send_esel(l_data, l_err, l_cc); // if no error but last completion code was: if ((l_err == NULL) && @@ -240,15 +175,31 @@ void IpmiSEL::process_esel(msg_t *i_msg) const if(l_err) { +#ifdef __HOSTBOOT_RUNTIME + // HBRT can't commit an error, since this could already be in the + // errlCommit path since HBRT is single threaded + IPMI_TRAC(ERR_MRK "DELETING l_err 0x%.8X", l_err->eid()); + delete l_err; + l_err = NULL; + + // TODO RTC: 123419 investigate adding a 'iv_isIpmiEnabled' flag and setting + // that to false somehow, so that we can commit error logs in this path + // and future calls wont try to send them down. +#else l_err->collectTrace(IPMI_COMP_NAME); errlCommit(l_err, IPMI_COMP_ID); +#endif } else if((l_cc == IPMI::CC_OK) && // no error (l_eid != 0)) // and it's an errorlog { +#ifdef __HOSTBOOT_RUNTIME + // TODO RTC: 123419 story to add storing errlog to PNOR in HBRT if IPMI +#else // eSEL successfully sent to the BMC - send an ack to the errlmanager IPMI_TRAC(INFO_MRK "Sending ack for eid 0x%.8X", l_eid); ERRORLOG::ErrlManager::errlAckErrorlog(l_eid); +#endif } delete l_data; @@ -260,8 +211,8 @@ void IpmiSEL::process_esel(msg_t *i_msg) const /* * @brief Send esel data to bmc */ -void IpmiSEL::send_esel(IPMISEL::eselInitData * i_data, - errlHndl_t &o_err, IPMI::completion_code &o_cc) const +void send_esel(IPMISEL::eselInitData * i_data, + errlHndl_t &o_err, IPMI::completion_code &o_cc) { IPMI_TRAC(ENTER_MRK "send_esel"); uint8_t* data = NULL; @@ -402,3 +353,83 @@ void IpmiSEL::send_esel(IPMISEL::eselInitData * i_data, return; } // send_esel +} // IPMISEL + +#ifndef __HOSTBOOT_RUNTIME +/** + * @brief Constructor + */ +IpmiSEL::IpmiSEL(void) + :iv_msgQ(msg_q_create()) +{ + IPMI_TRAC(ENTER_MRK "IpmiSEL ctor"); + task_create(&IpmiSEL::start,NULL); +} + +/** + * @brief Destructor + */ +IpmiSEL::~IpmiSEL(void) +{ + msg_q_destroy(iv_msgQ); +} + +void* IpmiSEL::start(void* unused) +{ + Singleton<IpmiSEL>::instance().execute(); + return NULL; +} + +/** + * @brief Entry point of the sel ipmi thread + */ +//@todo: RTC 119832 +void IpmiSEL::execute(void) +{ + //Mark as an independent daemon so if it crashes we terminate. + task_detach(); + + // Register shutdown events with init service. + // Done at the "end" of shutdown processesing. + // This will flush out any IPMI messages which were sent as + // part of the shutdown processing. We chose MBOX priority + // as we don't want to accidentally get this message after + // interrupt processing has stopped in case we need intr to + // finish flushing the pipe. + INITSERVICE::registerShutdownEvent(iv_msgQ, IPMISEL::MSG_STATE_SHUTDOWN, + INITSERVICE::MBOX_PRIORITY); + + while(true) + { + msg_t* msg = msg_wait(iv_msgQ); + + const IPMISEL::msg_type msg_type = + static_cast<IPMISEL::msg_type>(msg->type); + + // Invert the "default" by checking here. This allows the compiler + // to warn us if the enum has an unhadled case but still catch + // runtime errors where msg_type is set out of bounds. + assert(msg_type <= IPMISEL::MSG_LAST_TYPE, + "msg_type %d not handled", msg_type); + + switch(msg_type) + { + case IPMISEL::MSG_SEND_ESEL: + IPMISEL::process_esel(msg); + //done with msg + msg_free(msg); + break; + + case IPMISEL::MSG_STATE_SHUTDOWN: + IPMI_TRAC(INFO_MRK "ipmisel shutdown event"); + + //Respond that we are done shutting down. + msg_respond(iv_msgQ, msg); + break; + } + } // while(1) + IPMI_TRAC(EXIT_MRK "message loop"); + return; +} // execute +#endif + diff --git a/src/usr/ipmi/makefile b/src/usr/ipmi/makefile index 8dad57f3e..fb6a249a4 100644 --- a/src/usr/ipmi/makefile +++ b/src/usr/ipmi/makefile @@ -39,6 +39,7 @@ OBJS += ipmipowerstate.o OBJS += ipmiselrecord.o OBJS += ipmidcmi.o +SUBDIRS += runtime.d #SUBDIRS += test.d include ${ROOTPATH}/config.mk diff --git a/src/usr/ipmi/runtime/makefile b/src/usr/ipmi/runtime/makefile new file mode 100644 index 000000000..21ab138ff --- /dev/null +++ b/src/usr/ipmi/runtime/makefile @@ -0,0 +1,37 @@ +# IBM_PROLOG_BEGIN_TAG +# This is an automatically generated prolog. +# +# $Source: src/usr/ipmi/runtime/makefile $ +# +# OpenPOWER HostBoot Project +# +# Contributors Listed Below - COPYRIGHT 2015 +# [+] 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 +HOSTBOOT_RUNTIME = 1 +ROOTPATH = ../../../.. +MODULE = ipmi_rt + +OBJS += ipmisel.o +OBJS += ipmisensor.o +OBJS += rt_ipmirp.o + +SUBDIRS += test.d + +VPATH += .. +include $(ROOTPATH)/config.mk + diff --git a/src/usr/ipmi/runtime/rt_ipmirp.C b/src/usr/ipmi/runtime/rt_ipmirp.C new file mode 100644 index 000000000..7184c85f7 --- /dev/null +++ b/src/usr/ipmi/runtime/rt_ipmirp.C @@ -0,0 +1,142 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/ipmi/runtime/rt_ipmirp.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015 */ +/* [+] 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 */ +/** + * @file rt_ipmirp.C + * @brief IPMI resource provider definition for runtime + */ + +#include "../ipmirp.H" +#include "../ipmiconfig.H" +#include "../ipmidd.H" +#include <ipmi/ipmi_reasoncodes.H> +#include <ipmi/ipmiif.H> + +#include <config.h> +#include <sys/task.h> +#include <initservice/taskargs.H> +#include <initservice/initserviceif.H> +#include <sys/vfs.h> + +#include <targeting/common/commontargeting.H> +#include <kernel/ipc.H> +#include <arch/ppc.H> +#include <errl/errlmanager.H> +#include <sys/time.h> +#include <sys/misc.h> +#include <errno.h> +#include <runtime/interface.h> + +trace_desc_t * g_trac_ipmi; +#define IPMI_TRAC(printf_string,args...) \ + TRACFCOMP(g_trac_ipmi,"rt: "printf_string,##args) + +namespace IPMI +{ + // TODO RTC: 124099 move to a _hb attribute + // ATTR_IPMI_MAX_BUFFER_SEND_SIZE + static const size_t g_max_buffer = 61; + size_t max_buffer(void) + { + return g_max_buffer; + } + + /// + /// @brief Synchronus message send + /// + errlHndl_t sendrecv(const IPMI::command_t& i_cmd, + IPMI::completion_code& o_completion_code, + size_t& io_len, uint8_t*& io_data) + { + errlHndl_t err = NULL; + int rc = 0; + + // if the buffer is too large this is a programming error. + assert(io_len <= g_max_buffer); + + IPMI_TRAC("calling sync %x:%x len=%d", + i_cmd.first, i_cmd.second, io_len); + + if(g_hostInterfaces && g_hostInterfaces->ipmi_msg) + { + size_t l_len = g_max_buffer; // max size the BMC can return + uint8_t *l_data = new uint8_t[l_len]; + + rc = g_hostInterfaces->ipmi_msg( + i_cmd.first, i_cmd.second, + io_data, io_len, + l_data, &l_len); + + if(rc) + { + IPMI_TRAC(ERR_MRK + "Failed sending ipmi msg (%x:%x) to bmc rc: %d. ", + i_cmd.first, i_cmd.second, rc); + + /* @errorlog tag + * @errortype ERRL_SEV_UNRECOVERABLE + * @moduleid IPMI::MOD_IPMIRT + * @reasoncode IPMI::RC_INVALID_SENDRECV + * @userdata1[0:31] rc from ipmi_msg() + * @userdata1[32:46] netfn of failing msg + * @userdata1[47:63] cmd of failing msg + * @userdata2 length of failing msg + * @devdesc ipmi_msg() failed + * @custdesc Firmware error + */ + err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + IPMI::MOD_IPMIRT, + IPMI::RC_INVALID_SENDRECV, + TWO_UINT32_TO_UINT64(rc, + TWO_UINT16_TO_UINT32(i_cmd.first, i_cmd.second)), + io_len, + true); + err->collectTrace(IPMI_COMP_NAME); + delete[] io_data; + io_data = NULL; + io_len = 0; + } + else + { + // clean up the memory for the caller + o_completion_code = static_cast<IPMI::completion_code>(io_data[0]); + + // now need to create the buffer to return + io_len = l_len - 1; // get rid of the completion_code + delete[] io_data; + io_data = new uint8_t[io_len]; + memcpy(io_data, &l_data[1], io_len); // data after CC + } + delete[] l_data; + } + else + { + IPMI_TRAC(ERR_MRK + "Host interfaces not initialized; ipmi msg not sent. "); + } + + return err; + } // sendrecv +}; diff --git a/src/usr/ipmi/runtime/test/makefile b/src/usr/ipmi/runtime/test/makefile new file mode 100644 index 000000000..a12933112 --- /dev/null +++ b/src/usr/ipmi/runtime/test/makefile @@ -0,0 +1,31 @@ +# IBM_PROLOG_BEGIN_TAG +# This is an automatically generated prolog. +# +# $Source: src/usr/ipmi/runtime/test/makefile $ +# +# OpenPOWER HostBoot Project +# +# Contributors Listed Below - COPYRIGHT 2015 +# [+] 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 +HOSTBOOT_RUNTIME = 1 +ROOTPATH = ../../../../.. + +MODULE = testipmi_rt +TESTS = *.H + +include ${ROOTPATH}/config.mk diff --git a/src/usr/ipmi/runtime/test/rt_ipmitest.H b/src/usr/ipmi/runtime/test/rt_ipmitest.H new file mode 100644 index 000000000..b3a252e31 --- /dev/null +++ b/src/usr/ipmi/runtime/test/rt_ipmitest.H @@ -0,0 +1,102 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/ipmi/runtime/test/rt_ipmitest.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015 */ +/* [+] 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 */ +#ifndef __RT_IPMITEST_H +#define __RT_IPMITEST_H + +/** + * @file ipmitest.H + * + * @brief Test case for IPMI messages +*/ + +#include <cxxtest/TestSuite.H> + +#include "../../../trace/entry.H" + +#include <ipmi/ipmiif.H> +#include <ipmi/ipmisensor.H> + + +class RT_IpmiTest: public CxxTest::TestSuite +{ +public: + + + /** + * @brief call sendrecv directly + */ + void testIpmi1(void) + { + do + { + IPMI::completion_code cc = IPMI::CC_UNKBAD; + size_t len = 0; + uint8_t* data = NULL; + errlHndl_t err = IPMI::sendrecv(IPMI::get_capabilities(), cc, len, data); + + TS_WARN("testIpmi1: cc x%x, len %d", cc, len); + + if ( err != NULL ) + { + TS_FAIL("testIpmi1: get_capabilities() failed"); + break; + } + if (cc != IPMI::CC_OK) + { + TS_FAIL("testIpmi1: get_capabilities() failed with cc 0x%x", cc); + break; + } + if (len != 5) + { + TS_FAIL("testIpmi1: get_capabilities() returned len %d instead of 5", + len); + break; + } + + TS_WARN("testIpmi1: get_capabilities x%x, x%x x%x x%x x%x", + data[0], data[1], data[2], data[3], data[4]); + + } + while(0); + } + + /** + * @brief call IPMI::sensor function + */ + void testIpmi2(void) + { + do + { + uint8_t l_sensorNumber = SENSOR::getFaultSensorNumber( + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL); + + TS_WARN("testIpmi2: getFaultSensorNumber x%x", + l_sensorNumber); + } + while(0); + } +}; + +#endif diff --git a/src/usr/testcore/rtloader/loader.H b/src/usr/testcore/rtloader/loader.H index 041337118..9ac9c5ebc 100644 --- a/src/usr/testcore/rtloader/loader.H +++ b/src/usr/testcore/rtloader/loader.H @@ -41,6 +41,7 @@ #include <string.h> #include <devicefw/userif.H> #include <pnor/ecc.H> +#include <ipmi/ipmiif.H> trace_desc_t* g_trac_hbrt = NULL; TRAC_INIT(&g_trac_hbrt, "HBRT_TEST", 2*KILOBYTE); @@ -122,6 +123,7 @@ class RuntimeLoaderTest : public CxxTest::TestSuite intf->get_reserved_mem = rt_get_reserved_mem; intf->pnor_read = rt_pnor_read; intf->pnor_write= rt_pnor_write; + intf->ipmi_msg= rt_ipmi_msg; // Call init. runtimeInterfaces_t* rtInterface = @@ -518,6 +520,33 @@ class RuntimeLoaderTest : public CxxTest::TestSuite return cv_targ_addr; } + static int rt_ipmi_msg(uint8_t netfn, uint8_t cmd, + void *tx_buf, size_t tx_size, + void *rx_buf, size_t *rx_size) + { + TRACFCOMP(g_trac_hbrt, ENTER_MRK + "rt_ipmi_msg: tx_buf:%x/%x, size:%d, rx_buf:%p, size:%d", + netfn, cmd, tx_size, + rx_buf, *rx_size); + + errlHndl_t l_err = NULL; + do { + ((uint8_t*)rx_buf)[0] = IPMI::CC_OK; + rx_size = 0; + } while (0); + + //commit the error + uint32_t l_plid = 0; + if (l_err) + { + l_plid = l_err->plid(); + errlCommit (l_err, CXXTEST_COMP_ID); + } + TRACFCOMP(g_trac_hbrt, EXIT_MRK"rt_ipmi_msg"); + return l_plid; + } + + static uint64_t cv_vpd_addr; static uint64_t cv_vpd_phys_addr; static uint64_t cv_targ_addr; |