-
Notifications
You must be signed in to change notification settings - Fork 134
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ipmi: Add an opal interface to the ipmi stack
This patch adds two opal calls (opal_ipmi_send and opal_ipmi_recv) to allow an operating system to send and receive arbitrary ipmi messages to the BMC. Signed-off-by: Alistair Popple <alistair@popple.id.au> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
- Loading branch information
Showing
7 changed files
with
198 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
SUBDIRS += hw/ipmi | ||
|
||
IPMI_OBJS = ipmi-rtc.o ipmi-power.o | ||
IPMI_OBJS = ipmi-rtc.o ipmi-power.o ipmi-opal.o | ||
IPMI = hw/ipmi/built-in.o | ||
$(IPMI): $(IPMI_OBJS:%=hw/ipmi/%) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
/* Copyright 2013-2014 IBM 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. | ||
*/ | ||
|
||
#include <stdlib.h> | ||
#include <ipmi.h> | ||
#include <lock.h> | ||
#include <opal.h> | ||
#include <device.h> | ||
#include <ccan/list/list.h> | ||
|
||
enum { | ||
OPAL_IPMI_MSG_FORMAT_VERSION_1 = 1, | ||
}; | ||
|
||
struct opal_ipmi_msg { | ||
uint8_t version; | ||
uint8_t netfn; | ||
uint8_t cmd; | ||
uint8_t data[]; | ||
}; | ||
|
||
static struct lock msgq_lock = LOCK_UNLOCKED; | ||
static struct list_head msgq = LIST_HEAD_INIT(msgq); | ||
|
||
static void opal_send_complete(struct ipmi_msg *msg) | ||
{ | ||
lock(&msgq_lock); | ||
list_add_tail(&msgq, &msg->link); | ||
opal_update_pending_evt(ipmi_backend->opal_event_ipmi_recv, | ||
ipmi_backend->opal_event_ipmi_recv); | ||
unlock(&msgq_lock); | ||
} | ||
|
||
static int64_t opal_ipmi_send(uint64_t interface, | ||
struct opal_ipmi_msg *opal_ipmi_msg, uint64_t msg_len) | ||
{ | ||
struct ipmi_msg *msg; | ||
|
||
if (opal_ipmi_msg->version != OPAL_IPMI_MSG_FORMAT_VERSION_1) { | ||
prerror("OPAL IPMI: Incorrect version\n"); | ||
return OPAL_UNSUPPORTED; | ||
} | ||
|
||
msg_len -= sizeof(struct opal_ipmi_msg); | ||
if (msg_len > IPMI_MAX_REQ_SIZE) { | ||
prerror("OPAL IPMI: Invalid request length\n"); | ||
return OPAL_PARAMETER; | ||
} | ||
|
||
prlog(PR_DEBUG, "opal_ipmi_send(cmd: 0x%02x netfn: 0x%02x len: 0x%02llx)\n", | ||
opal_ipmi_msg->cmd, opal_ipmi_msg->netfn >> 2, msg_len); | ||
|
||
msg = ipmi_mkmsg(interface, | ||
IPMI_CODE(opal_ipmi_msg->netfn >> 2, opal_ipmi_msg->cmd), | ||
opal_send_complete, NULL, opal_ipmi_msg->data, | ||
msg_len, IPMI_MAX_RESP_SIZE); | ||
if (!msg) | ||
return OPAL_RESOURCE; | ||
|
||
msg->complete = opal_send_complete; | ||
msg->error = opal_send_complete; | ||
return ipmi_queue_msg(msg); | ||
} | ||
|
||
static int64_t opal_ipmi_recv(uint64_t interface, | ||
struct opal_ipmi_msg *opal_ipmi_msg, uint64_t *msg_len) | ||
{ | ||
struct ipmi_msg *msg; | ||
int64_t rc; | ||
|
||
lock(&msgq_lock); | ||
msg = list_top(&msgq, struct ipmi_msg, link); | ||
|
||
if (!msg) { | ||
rc = OPAL_EMPTY; | ||
goto out_unlock; | ||
} | ||
|
||
if (opal_ipmi_msg->version != OPAL_IPMI_MSG_FORMAT_VERSION_1) { | ||
prerror("OPAL IPMI: Incorrect version\n"); | ||
rc = OPAL_UNSUPPORTED; | ||
goto out_unlock; | ||
} | ||
|
||
if (interface != IPMI_DEFAULT_INTERFACE) { | ||
prerror("IPMI: Invalid interface 0x%llx in opal_ipmi_recv\n", interface); | ||
rc = OPAL_EMPTY; | ||
goto out_unlock; | ||
} | ||
|
||
if (*msg_len - sizeof(struct opal_ipmi_msg) < msg->resp_size + 1) { | ||
rc = OPAL_RESOURCE; | ||
goto out_unlock; | ||
} | ||
|
||
list_del(&msg->link); | ||
if (list_empty(&msgq)) | ||
opal_update_pending_evt(ipmi_backend->opal_event_ipmi_recv, 0); | ||
unlock(&msgq_lock); | ||
|
||
opal_ipmi_msg->cmd = msg->cmd; | ||
opal_ipmi_msg->netfn = msg->netfn; | ||
opal_ipmi_msg->data[0] = msg->cc; | ||
memcpy(&opal_ipmi_msg->data[1], msg->data, msg->resp_size); | ||
|
||
prlog(PR_DEBUG, "opal_ipmi_recv(cmd: 0x%02x netfn: 0x%02x resp_size: 0x%02x)\n", | ||
msg->cmd, msg->netfn >> 2, msg->resp_size); | ||
|
||
/* Add one as the completion code is returned in the message data */ | ||
*msg_len = msg->resp_size + sizeof(struct opal_ipmi_msg) + 1; | ||
ipmi_free_msg(msg); | ||
|
||
return OPAL_SUCCESS; | ||
|
||
out_unlock: | ||
unlock(&msgq_lock); | ||
return rc; | ||
} | ||
|
||
void ipmi_opal_init(void) | ||
{ | ||
struct dt_node *opal_ipmi; | ||
|
||
opal_ipmi = dt_new(opal_node, "ipmi"); | ||
dt_add_property_strings(opal_ipmi, "compatible", "ibm,opal-ipmi"); | ||
dt_add_property_cells(opal_ipmi, "ibm,ipmi-interface-id", | ||
IPMI_DEFAULT_INTERFACE); | ||
dt_add_property_cells(opal_ipmi, "interrupts", | ||
ilog2(ipmi_backend->opal_event_ipmi_recv)); | ||
|
||
opal_register(OPAL_IPMI_SEND, opal_ipmi_send, 3); | ||
opal_register(OPAL_IPMI_RECV, opal_ipmi_recv, 3); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters