@@ -103,6 +103,46 @@ void ipmi_cmd_done(uint8_t cmd, uint8_t netfn, uint8_t cc, struct ipmi_msg *msg)
completion functions. */
}
+static void ipmi_read_event_complete(struct ipmi_msg *msg)
+{
+ prlog(PR_DEBUG, "IPMI read event %02x complete: %d bytes. cc: %02x\n",
+ msg->cmd, msg->resp_size, msg->cc);
+
+ /* TODO: Handle power control & PNOR handshake events */
+
+ ipmi_free_msg(msg);
+}
+
+static void ipmi_get_message_flags_complete(struct ipmi_msg *msg)
+{
+ uint8_t flags = msg->data[0];
+
+ ipmi_free_msg(msg);
+
+ prlog(PR_DEBUG, "IPMI Get Message Flags: %02x\n", flags);
+
+ /* Message available in the event buffer? Queue a Read Event command
+ * to retrieve it. The flag is cleared by performing a read */
+ if (flags & IPMI_MESSAGE_FLAGS_EVENT_BUFFER) {
+ msg = ipmi_mkmsg(IPMI_DEFAULT_INTERFACE, IPMI_READ_EVENT,
+ ipmi_read_event_complete, NULL, NULL, 0, 16);
+ ipmi_queue_msg(msg);
+ }
+}
+
+void ipmi_sms_attention(void)
+{
+ struct ipmi_msg *msg;
+
+ /* todo: when we handle multiple IPMI interfaces, we'll need to
+ * ensure that this message is associated with the appropriate
+ * backend. */
+ msg = ipmi_mkmsg(IPMI_DEFAULT_INTERFACE, IPMI_GET_MESSAGE_FLAGS,
+ ipmi_get_message_flags_complete, NULL, NULL, 0, 1);
+
+ ipmi_queue_msg(msg);
+}
+
void ipmi_register_backend(struct ipmi_backend *backend)
{
/* We only support one backend at the moment */
@@ -418,12 +418,18 @@ static int bt_add_ipmi_msg(struct ipmi_msg *ipmi_msg)
void bt_irq(void)
{
uint8_t ireg = bt_inb(BT_INTMASK);
+ uint8_t ctrl = bt_inb(BT_CTRL);
bt.irq_ok = true;
if (ireg & BT_INTMASK_B2H_IRQ) {
bt_outb(BT_INTMASK_B2H_IRQ | BT_INTMASK_B2H_IRQEN, BT_INTMASK);
bt_poll(NULL, NULL);
}
+
+ if (ctrl & BT_CTRL_SMS_ATN) {
+ bt_outb(BT_CTRL_SMS_ATN, BT_CTRL);
+ ipmi_sms_attention();
+ }
}
/*
@@ -76,6 +76,14 @@
#define IPMI_PWR_SYS_UNKNOWN 0x2a
#define IPMI_PWR_NOCHANGE 0x7f
+/* 22.{3,4} Clear / Get message flags */
+#define IPMI_MESSAGE_FLAGS_RX_MESSAGE_QUEUE (1<<0)
+#define IPMI_MESSAGE_FLAGS_EVENT_BUFFER (1<<1)
+#define IPMI_MESSAGE_FLAGS_WATCHDOG_PRE_TIMEOUT (1<<3)
+#define IPMI_MESSAGE_FLAGS_OEM0 (1<<5)
+#define IPMI_MESSAGE_FLAGS_OEM1 (1<<6)
+#define IPMI_MESSAGE_FLAGS_OEM2 (1<<7)
+
#define IPMI_CODE(netfn, cmd) ((netfn) << 8 | (cmd))
#define IPMI_CMD(code) ((code) & 0xff)
#define IPMI_NETFN(code) ((code) >> 8 & 0xff)
@@ -93,6 +101,10 @@
#define IPMI_CHASSIS_CONTROL IPMI_CODE(IPMI_NETFN_CHASSIS, 0x02)
#define IPMI_SET_POWER_STATE IPMI_CODE(IPMI_NETFN_APP, 0x06)
#define IPMI_GET_POWER_STATE IPMI_CODE(IPMI_NETFN_APP, 0x07)
+#define IPMI_CLEAR_MESSAGE_FLAGS IPMI_CODE(IPMI_NETFN_APP, 0x30)
+#define IPMI_GET_MESSAGE_FLAGS IPMI_CODE(IPMI_NETFN_APP, 0x31)
+#define IPMI_GET_MESSAGE IPMI_CODE(IPMI_NETFN_APP, 0x33)
+#define IPMI_READ_EVENT IPMI_CODE(IPMI_NETFN_APP, 0x35)
#define IPMI_PARTIAL_ADD_ESEL IPMI_CODE(IPMI_NETFN_OEM, 0xf0)
@@ -163,6 +175,9 @@ struct ipmi_msg *ipmi_mkmsg(int interface, uint32_t code,
void *user_data, void *req_data, size_t req_size,
size_t resp_size);
+/* called by backend code to indicate a SMS_ATN event */
+void ipmi_sms_attention(void);
+
/* Add an ipmi message to the queue */
int ipmi_queue_msg(struct ipmi_msg *msg);