aboutsummaryrefslogtreecommitdiff
path: root/hw/bt.c
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 /hw/bt.c
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>
Diffstat (limited to 'hw/bt.c')
-rw-r--r--hw/bt.c79
1 files changed, 19 insertions, 60 deletions
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);
}