summaryrefslogtreecommitdiffstats
path: root/src/usr/ipmi
diff options
context:
space:
mode:
authorBill Schwartz <whs@us.ibm.com>2014-10-30 07:29:56 -0500
committerA. Patrick Williams III <iawillia@us.ibm.com>2014-12-01 16:07:34 -0600
commit90b6464a0364c1bb86ad490c3807dcbbaab3b26b (patch)
treed67fd5142ed026198b8bc7bdcb7a0035a43c5b72 /src/usr/ipmi
parentcae9d6a9bfdb1834aa5015ffedc7b1f7025ad7b9 (diff)
downloadtalos-hostboot-90b6464a0364c1bb86ad490c3807dcbbaab3b26b.tar.gz
talos-hostboot-90b6464a0364c1bb86ad490c3807dcbbaab3b26b.zip
BMC: Shutdown handling in IPMI Resource
Quiesce activity and free resources Depends-on: I2a763e5e3ea59e6afb7b7ab7d088fb236ee3428e Change-Id: Id801368fb81f0421c7b11e96898142548417db5c RTC: 106887 Reviewed-on: http://gfw160.aus.stglabs.ibm.com:8080/gerrit/14251 Tested-by: Jenkins Server Reviewed-by: Brian Silver <bsilver@us.ibm.com> Reviewed-by: ANIRUDH BAGEPALLI <abagepa@us.ibm.com> Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
Diffstat (limited to 'src/usr/ipmi')
-rw-r--r--src/usr/ipmi/ipmidd.C42
-rw-r--r--src/usr/ipmi/ipmidd.H10
-rw-r--r--src/usr/ipmi/ipmirp.C78
-rw-r--r--src/usr/ipmi/ipmirp.H9
4 files changed, 122 insertions, 17 deletions
diff --git a/src/usr/ipmi/ipmidd.C b/src/usr/ipmi/ipmidd.C
index 4484daca5..7e5e3722c 100644
--- a/src/usr/ipmi/ipmidd.C
+++ b/src/usr/ipmi/ipmidd.C
@@ -208,6 +208,8 @@ static void* poll_control_register( void* /* unused */ )
*/
void IpmiDD::pollCtrl(void)
{
+ IPMI_TRAC(ENTER_MRK "poll_control_register" );
+
// Mark as an independent daemon so if it crashes we terminate.
task_detach();
@@ -222,12 +224,14 @@ void IpmiDD::pollCtrl(void)
while(1)
{
mutex_lock(&iv_mutex);
+
errlHndl_t err = readLPC(REG_CONTROL, ctrl);
// Not sure there's much we can do here but commit the log
// and let this thread fail.
if (err)
{
+ mutex_unlock(&iv_mutex);
IPMI_TRAC(ERR_MRK "polling loop encountered an error, exiting");
errlCommit(err, IPMI_COMP_ID);
break;
@@ -238,14 +242,22 @@ void IpmiDD::pollCtrl(void)
// pending messages which were delayed due to contention. But don't
// send a message everytime we see idle, only if there we suspect
// we sent EAGAINs.
- if (((ctrl & IDLE_STATE) == 0) && iv_eagains)
+ if ((ctrl & IDLE_STATE) == 0)
{
- msg = msg_allocate();
- msg->type = IPMI::MSG_STATE_IDLE;
- msg_send(mq, msg);
- iv_eagains = false;
+ if (iv_eagains)
+ {
+ msg = msg_allocate();
+ msg->type = IPMI::MSG_STATE_IDLE;
+ msg_send(mq, msg);
+ iv_eagains = false;
+ }
+ // Check on shutdown if idle
+ else if (iv_shutdown_now)
+ {
+ mutex_unlock(&iv_mutex);
+ break; // exit loop and terminate task
+ }
}
-
// If we see the B2H_ATN, there's a response waiting
else if (ctrl & CTRL_B2H_ATN)
{
@@ -264,8 +276,10 @@ void IpmiDD::pollCtrl(void)
}
}
mutex_unlock(&iv_mutex);
+
nanosleep(0, WAIT_TIME);
}
+ IPMI_TRAC(EXIT_MRK "poll_control_register" );
}
/**
@@ -473,9 +487,25 @@ errlHndl_t IpmiDD::receive(IPMI::BTMessage* o_msg)
}
/**
+ * @brief shutdown the device driver
+ */
+void IpmiDD::handleShutdown(void)
+{
+ IPMI_TRAC(ENTER_MRK "handle Shutdown" );
+ mutex_lock(&iv_mutex);
+ iv_shutdown_now = true; // signal poll controller to terminate
+
+ // TODO: RTC 116600 mask interrupts
+
+ mutex_unlock(&iv_mutex);
+ IPMI_TRAC(EXIT_MRK "handle Shutdown" );
+}
+
+/**
* @brief Constructor
*/
IpmiDD::IpmiDD(void):
+ iv_shutdown_now(false),
iv_eagains(false)
{
mutex_init(&iv_mutex);
diff --git a/src/usr/ipmi/ipmidd.H b/src/usr/ipmi/ipmidd.H
index d20dd6132..2faed9b3b 100644
--- a/src/usr/ipmi/ipmidd.H
+++ b/src/usr/ipmi/ipmidd.H
@@ -76,6 +76,11 @@ class IpmiDD
errlHndl_t reset(void);
/**
+ * @brief shutdown the device driver
+ */
+ void handleShutdown(void);
+
+ /**
* @brief Constructor
*
* @parm void
@@ -111,6 +116,11 @@ class IpmiDD
mutex_t iv_mutex;
/**
+ * @brief Shut down resources
+ */
+ bool iv_shutdown_now;
+
+ /**
* @brief True if we told the RP to try a write again
*/
bool iv_eagains;
diff --git a/src/usr/ipmi/ipmirp.C b/src/usr/ipmi/ipmirp.C
index 12b5015a2..9265e06b7 100644
--- a/src/usr/ipmi/ipmirp.C
+++ b/src/usr/ipmi/ipmirp.C
@@ -29,6 +29,7 @@
#include "ipmirp.H"
#include "ipmiconfig.H"
+#include "ipmidd.H"
#include <ipmi/ipmi_reasoncodes.H>
#include <devicefw/driverif.H>
#include <devicefw/userif.H>
@@ -69,7 +70,9 @@ IpmiRP::IpmiRP(void):
iv_outstanding_req(IPMI::g_outstanding_req),
iv_xmit_buffer_size(IPMI::g_xmit_buffer_size),
iv_recv_buffer_size(IPMI::g_recv_buffer_size),
- iv_retries(IPMI::g_retries)
+ iv_retries(IPMI::g_retries),
+ iv_shutdown_msg(NULL),
+ iv_shutdown_now(false)
{
mutex_init(&iv_mutex);
sync_cond_init(&iv_cv);
@@ -152,6 +155,8 @@ void IpmiRP::timeoutThread(void)
// Mark as an independent daemon so if it crashes we terminate.
task_detach();
+ IPMI_TRAC(ENTER_MRK "time out thread");
+
// If there's something on the queue we want to grab it's timeout time
// and wait. Note the response queue is "sorted" as we send messages in
// order. So, the first message on the queue is the one who's timeout
@@ -159,11 +164,17 @@ void IpmiRP::timeoutThread(void)
while (true)
{
mutex_lock(&iv_mutex);
- while (iv_timeoutq.size() == 0)
+ while ((iv_timeoutq.size() == 0) && !iv_shutdown_now)
{
sync_cond_wait(&iv_cv, &iv_mutex);
}
+ // shutting down...
+ if (iv_shutdown_now)
+ {
+ break; // return and terminate thread
+ }
+
msg_t*& msq_msg = iv_timeoutq.front();
IPMI::Message* msg = static_cast<IPMI::Message*>(msq_msg->extra_data);
@@ -186,6 +197,12 @@ void IpmiRP::timeoutThread(void)
// Get him off the responseq, and reply back to the waiter that
// there was a timeout
response(msg, IPMI::CC_TIMEOUT);
+
+ // Tell the resource provider to check for any pending messages
+ msg_t* msg_idleMsg = msg_allocate();
+ msg_idleMsg->type = IPMI::MSG_STATE_IDLE;
+ msg_send(iv_msgQ, msg_idleMsg);
+
mutex_unlock(&iv_mutex);
}
else
@@ -194,6 +211,7 @@ void IpmiRP::timeoutThread(void)
nanosleep( 0, timeout - now );
}
}
+ IPMI_TRAC(EXIT_MRK "time out thread");
return;
}
@@ -266,7 +284,7 @@ void IpmiRP::getInterfaceCapabilities(void)
*/
void IpmiRP::execute(void)
{
- bool shutdown_pending = false;
+ bool l_shutdown_pending = false;
// Mark as an independent daemon so if it crashes we terminate.
task_detach();
@@ -307,7 +325,19 @@ void IpmiRP::execute(void)
// bottom of this loop will start the transmit process.
// Be sure to push_back to ensure ordering of transmission.
case IPMI::MSG_STATE_SEND:
- iv_sendq.push_back(msg);
+ if (!l_shutdown_pending)
+ {
+ iv_sendq.push_back(msg);
+ }
+ // shutting down, do not accept new messages
+ else
+ {
+ IPMI_TRAC(WARN_MRK "IPMI shutdown pending. Message dropped");
+ IPMI::Message* ipmi_msg =
+ static_cast<IPMI::Message*>(msg->extra_data);
+ response(ipmi_msg, IPMI::CC_BADSTATE);
+ msg_free(msg);
+ }
break;
// State changes from the IPMI hardware. These are async
@@ -333,8 +363,9 @@ void IpmiRP::execute(void)
// Accept no more messages. Anything in the sendq is sent and
// we wait for the reply from the BMC.
case IPMI::MSG_STATE_SHUTDOWN:
- IPMI_TRAC(INFO_MRK "ipmi shutting down");
- shutdown_pending = true;
+ IPMI_TRAC(INFO_MRK "ipmi begin shutdown");
+ l_shutdown_pending = true; // Stop incoming new messages
+ iv_shutdown_msg = msg; // Reply to this message
break;
};
@@ -350,12 +381,11 @@ void IpmiRP::execute(void)
idle();
}
- // TODO: RTC 106887 Hold off transmitters, drain queues.
- // Patrick suggests handling this like mailboxes.
- if (shutdown_pending && iv_respondq.empty() && iv_sendq.empty())
+ // Once quiesced, shutdown and reply to shutdown msg
+ if (l_shutdown_pending && iv_respondq.empty() && iv_sendq.empty())
{
- msg_respond(iv_msgQ, msg);
- break;
+ shutdownNow();
+ break; // exit loop and terminate task
}
}
@@ -559,6 +589,32 @@ void IpmiRP::queueForResponse(IPMI::Message& i_msg)
return;
}
+///
+/// @brief handle shutdown.
+/// Queued messages to send have been sent and all responses complete.
+/// Now that we are quiesced, deallocate resources and respond to the
+/// shutdown message
+///
+void IpmiRP::shutdownNow(void)
+{
+ IPMI_TRAC(INFO_MRK "ipmi shut down now");
+
+ mutex_lock(&iv_mutex);
+ iv_shutdown_now = true; // Shutdown underway
+
+ // Wake up Time out thread to terminate.
+ sync_cond_signal(&iv_cv);
+ mutex_unlock(&iv_mutex);
+
+ // TODO: RTC 116600 unRegisterMsgQ for interrupts
+
+ // Shut down device driver
+ Singleton<IpmiDD>::instance().handleShutdown();
+
+ // reply back to shutdown requester that we are shutdown
+ msg_respond(iv_msgQ, iv_shutdown_msg);
+}
+
namespace IPMI
{
diff --git a/src/usr/ipmi/ipmirp.H b/src/usr/ipmi/ipmirp.H
index 2edf24e9a..d1ebaad7d 100644
--- a/src/usr/ipmi/ipmirp.H
+++ b/src/usr/ipmi/ipmirp.H
@@ -193,6 +193,12 @@ class IpmiRP
*/
void getInterfaceCapabilities(void);
+ /**
+ * @brief Clean up resources and reply to shutdown msg
+ * @param[in] void
+ */
+ void shutdownNow(void);
+
msg_q_t iv_msgQ; //!< ipmi mesage queue
IPMI::send_q_t iv_sendq; //!< msg to send queue
IPMI::timeout_q_t iv_timeoutq; //!< msgs waiting for a timeout
@@ -218,6 +224,9 @@ class IpmiRP
// Recomended number of retries
uint8_t iv_retries;
+ // Shutdown
+ msg_t * iv_shutdown_msg; //!< shutdown msg to respond to
+ bool iv_shutdown_now; //!< shutdown now
// Disallow copying this class.
IpmiRP& operator=(const IpmiRP&);
OpenPOWER on IntegriCloud