aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlistair Popple <alistair@popple.id.au>2014-09-09 15:57:28 +1000
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2014-10-01 14:23:06 +1000
commit78a2da4ca3b5362b7b9ba5632e6d4287a3c3263e (patch)
treee95966cf69430852b3a54439f502d3b64072a98c
parentf671e7f9decd909afa784f974bbceb07189f38f4 (diff)
downloadskiboot-78a2da4ca3b5362b7b9ba5632e6d4287a3c3263e.zip
skiboot-78a2da4ca3b5362b7b9ba5632e6d4287a3c3263e.tar.gz
skiboot-78a2da4ca3b5362b7b9ba5632e6d4287a3c3263e.tar.bz2
bt/ipmi: Convert to using asynchronous messaging
Previously we were doing synchronous messaging and cranking the bt state machine from within OPAL. This was not ideal as it could potentially take control away from the OS for long periods of time if the BMC is busy. This patch solves the problem using the opal_poll api to do asynchronous messaging. Signed-off-by: Alistair Popple <alistair@popple.id.au> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-rw-r--r--core/ipmi.c2
-rw-r--r--hw/bt.c79
-rw-r--r--hw/ipmi/ipmi-power.c2
-rw-r--r--hw/ipmi/ipmi-rtc.c39
-rw-r--r--include/ipmi.h3
5 files changed, 52 insertions, 73 deletions
diff --git a/core/ipmi.c b/core/ipmi.c
index 90d8aaf..488e7e9 100644
--- a/core/ipmi.c
+++ b/core/ipmi.c
@@ -63,7 +63,7 @@ struct ipmi_msg *ipmi_mkmsg(int interface, uint32_t code,
return msg;
}
-int ipmi_sync_queue_msg(struct ipmi_msg *msg)
+int ipmi_queue_msg(struct ipmi_msg *msg)
{
/* Here we could choose which interface to use if we want to support
multiple interfaces. */
diff --git a/hw/bt.c b/hw/bt.c
index 882d72c..ec67154 100644
--- a/hw/bt.c
+++ b/hw/bt.c
@@ -116,8 +116,10 @@ static int bt_add_ipmi_msg(struct ipmi_msg *ipmi_msg)
struct bt_msg *bt_msg = container_of(ipmi_msg, struct bt_msg, ipmi_msg);
bt_msg->lun = 0;
+ lock(&bt.lock);
bt_msg->seq = ipmi_seq++;
list_add_tail(&bt.msgq, &bt_msg->link);
+ unlock(&bt.lock);
return 0;
}
@@ -134,15 +136,19 @@ static bool bt_try_send_msg(void)
struct bt_msg *bt_msg;
struct ipmi_msg *ipmi_msg;
+ lock(&bt.lock);
bt_msg = list_top(&bt.msgq, struct bt_msg, link);
- if (!bt_msg)
+ if (!bt_msg) {
+ unlock(&bt.lock);
return true;
+ }
ipmi_msg = &bt_msg->ipmi_msg;
if (!bt_idle()) {
prerror("BT: Interface in an unexpected state, attempting reset\n");
bt_reset_interface();
+ unlock(&bt.lock);
return false;
}
@@ -167,6 +173,8 @@ static bool bt_try_send_msg(void)
bt_setmask(BT_CTRL_H2B_ATN, BT_CTRL);
bt_set_state(BT_STATE_RESP_WAIT);
+ unlock(&bt.lock);
+
return true;
}
@@ -188,8 +196,11 @@ static bool bt_get_resp(void)
uint8_t cc = IPMI_CC_NO_ERROR;
/* Wait for BMC to signal response */
- if (!(bt_inb(BT_CTRL) & BT_CTRL_B2H_ATN))
+ lock(&bt.lock);
+ if (!(bt_inb(BT_CTRL) & BT_CTRL_B2H_ATN)) {
+ unlock(&bt.lock);
return true;
+ }
bt_msg = list_top(&bt.msgq, struct bt_msg, link);
if (!bt_msg) {
@@ -197,6 +208,7 @@ static bool bt_get_resp(void)
prlog(PR_INFO, "BT: Nobody cared about a response to an BT/IPMI message\n");
bt_flush_msg();
bt_set_state(BT_STATE_B_BUSY);
+ unlock(&bt.lock);
return false;
}
@@ -248,6 +260,7 @@ static bool bt_get_resp(void)
/* Make sure the other side is idle before we move to the idle state */
bt_set_state(BT_STATE_B_BUSY);
list_del(&bt_msg->link);
+ unlock(&bt.lock);
/*
* Call the IPMI layer to finish processing the message.
@@ -258,7 +271,7 @@ static bool bt_get_resp(void)
return false;
}
-static void bt_poll(void)
+static void bt_poll(void *data __unused)
{
bool ret = true;
@@ -284,27 +297,6 @@ static void bt_poll(void)
}
/*
- * Crank the state machine to wait for a specific state. Returns true on
- * success and false if there is a timeout.
- */
-static bool bt_wait_state(enum bt_states state)
-{
- int timeout;
- struct timespec ts;
-
- ts.tv_sec = 0;
- ts.tv_nsec = 100000;
- for (timeout = POLL_TIMEOUT; timeout > 0; timeout--) {
- if (bt.state == state)
- return true;
- bt_poll();
- nanosleep(&ts, NULL);
- }
-
- return false;
-}
-
-/*
* Allocate an ipmi message and bt container and return the ipmi
* message struct. Allocates enough space for the request and response
* data.
@@ -335,41 +327,6 @@ static void bt_free_ipmi_msg(struct ipmi_msg *ipmi_msg)
}
/*
- * Add an ipmi message to the queue and wait for a response.
- */
-static int bt_add_ipmi_msg_wait(struct ipmi_msg *msg)
-{
- int ret = 0;
-
- /*
- * TODO: We may need finer grained locks if we start using an
- * asynchronous operation model, but this should be fine for the moment.
- */
- lock(&bt.lock);
- if (!bt_wait_state(BT_STATE_IDLE)) {
- ret = -1;
- goto out;
- }
-
- if (bt_add_ipmi_msg(msg)) {
- ret = -1;
- goto out;
- }
-
- /* Make sure we get out of the idle state */
- bt_poll();
-
- if (!bt_wait_state(BT_STATE_IDLE)) {
- ret = -1;
- goto out;
- }
-
-out:
- unlock(&bt.lock);
- return ret;
-}
-
-/*
* Remove a message from the queue. The memory allocated for the ipmi message
* will need to be freed by the caller with bt_free_ipmi_msg() as it will no
* longer be in the queue of messages.
@@ -387,7 +344,7 @@ static int bt_del_ipmi_msg(struct ipmi_msg *ipmi_msg)
struct ipmi_backend bt_backend = {
.alloc_msg = bt_alloc_ipmi_msg,
.free_msg = bt_free_ipmi_msg,
- .queue_msg = bt_add_ipmi_msg_wait,
+ .queue_msg = bt_add_ipmi_msg,
.dequeue_msg = bt_del_ipmi_msg,
};
@@ -422,5 +379,7 @@ void bt_init(void)
bt_set_state(BT_STATE_B_BUSY);
list_head_init(&bt.msgq);
+ opal_add_poller(bt_poll, NULL);
+
ipmi_register_backend(&bt_backend);
}
diff --git a/hw/ipmi/ipmi-power.c b/hw/ipmi/ipmi-power.c
index ac37d14..c8589c1 100644
--- a/hw/ipmi/ipmi-power.c
+++ b/hw/ipmi/ipmi-power.c
@@ -36,5 +36,5 @@ int64_t ipmi_opal_chassis_control(uint64_t request)
prlog(PR_INFO, "IPMI: sending chassis control request %llu\n",
request);
- return ipmi_sync_queue_msg(msg);
+ return ipmi_queue_msg(msg);
}
diff --git a/hw/ipmi/ipmi-rtc.c b/hw/ipmi/ipmi-rtc.c
index 5ddfced..7ac33ff 100644
--- a/hw/ipmi/ipmi-rtc.c
+++ b/hw/ipmi/ipmi-rtc.c
@@ -24,15 +24,17 @@
/* Sane default (2014/01/01) */
static time_t time = 1388494800;
+static enum {idle, waiting, updated} time_status;
+
static void get_sel_time_complete(struct ipmi_msg *msg)
{
uint32_t result;
memcpy(&result, msg->data, 4);
time = le32_to_cpu(result);
+ time_status = updated;
}
-
static int64_t ipmi_get_sel_time(void)
{
struct ipmi_msg *msg;
@@ -42,7 +44,7 @@ static int64_t ipmi_get_sel_time(void)
if (!msg)
return OPAL_HARDWARE;
- return ipmi_sync_queue_msg(msg);
+ return ipmi_queue_msg(msg);
}
static int64_t ipmi_set_sel_time(uint32_t tv)
@@ -54,20 +56,37 @@ static int64_t ipmi_set_sel_time(uint32_t tv)
if (!msg)
return OPAL_HARDWARE;
- return ipmi_sync_queue_msg(msg);
+ return ipmi_queue_msg(msg);
}
+void bt_poll(void *data __unused);
static int64_t ipmi_opal_rtc_read(uint32_t *y_m_d,
uint64_t *h_m_s_m)
{
struct tm tm;
-
- if (ipmi_get_sel_time() < 0)
- return OPAL_HARDWARE;
-
- gmtime_r(&time, &tm);
- tm_to_datetime(&tm, y_m_d, h_m_s_m);
- return OPAL_SUCCESS;
+ int ret = 0;
+
+ switch(time_status) {
+ case idle:
+ if (ipmi_get_sel_time() < 0)
+ return OPAL_HARDWARE;
+ time_status = waiting;
+ ret = OPAL_BUSY_EVENT;
+ break;
+
+ case waiting:
+ ret = OPAL_BUSY_EVENT;
+ break;
+
+ case updated:
+ gmtime_r(&time, &tm);
+ tm_to_datetime(&tm, y_m_d, h_m_s_m);
+ time_status = idle;
+ ret = OPAL_SUCCESS;
+ break;
+ }
+
+ return ret;
}
static int64_t ipmi_opal_rtc_write(uint32_t year_month_day,
diff --git a/include/ipmi.h b/include/ipmi.h
index 78eb5cd..643dbf4 100644
--- a/include/ipmi.h
+++ b/include/ipmi.h
@@ -129,7 +129,8 @@ struct ipmi_msg *ipmi_mkmsg(int interface, uint32_t code,
void *user_data, void *req_data, size_t req_size,
size_t resp_size);
-int ipmi_sync_queue_msg(struct ipmi_msg *msg);
+/* Add an ipmi message to the queue */
+int ipmi_queue_msg(struct ipmi_msg *msg);
/* Process a completed message */
void ipmi_cmd_done(struct ipmi_msg *msg);