aboutsummaryrefslogtreecommitdiff
path: root/hw/bt.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2014-10-05 09:19:04 +1100
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2014-10-05 09:19:04 +1100
commitd09b52b8982db63525c67bf36506ce8a813f84d0 (patch)
treecbe3554b6d2c1ff8e358623264b7004b79ae84f2 /hw/bt.c
parentb33fd8dc893e2ea65ceef5dad2fa8173932443e5 (diff)
downloadskiboot-d09b52b8982db63525c67bf36506ce8a813f84d0.zip
skiboot-d09b52b8982db63525c67bf36506ce8a813f84d0.tar.gz
skiboot-d09b52b8982db63525c67bf36506ce8a813f84d0.tar.bz2
ipmi/bt: Rework iBT register access
The bits in the control register are mostly write-1-to-clear, so the rmw sequences in bt_setmask() and bt_clearmask() don't work. Additionally, H_BUSY is weird as it's a write-1-to-toggle, so let's write a "safe" function that sets it to the desired state based on its previous state. (We can optimize that further later). Also enable interrupt operations. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'hw/bt.c')
-rw-r--r--hw/bt.c87
1 files changed, 54 insertions, 33 deletions
diff --git a/hw/bt.c b/hw/bt.c
index 3aa14f3..561ed14 100644
--- a/hw/bt.c
+++ b/hw/bt.c
@@ -24,17 +24,19 @@
/* BT registers */
#define BT_CTRL 0
-#define BT_CTRL_B_BUSY 0x00000080
-#define BT_CTRL_H_BUSY 0x00000040
-#define BT_CTRL_OEM0 0x00000020
-#define BT_CTRL_SMS_ATN 0x00000010
-#define BT_CTRL_B2H_ATN 0x00000008
-#define BT_CTRL_H2B_ATN 0x00000004
-#define BT_CTRL_CLR_RD_PTR 0x00000002
-#define BT_CTRL_CLR_WR_PTR 0x00000001
+#define BT_CTRL_B_BUSY 0x80
+#define BT_CTRL_H_BUSY 0x40
+#define BT_CTRL_OEM0 0x20
+#define BT_CTRL_SMS_ATN 0x10
+#define BT_CTRL_B2H_ATN 0x08
+#define BT_CTRL_H2B_ATN 0x04
+#define BT_CTRL_CLR_RD_PTR 0x02
+#define BT_CTRL_CLR_WR_PTR 0x01
#define BT_HOST2BMC 1
#define BT_INTMASK 2
-#define BT_INTMASK_BMC_HWRST 0x00000001
+#define BT_INTMASK_B2H_IRQEN 0x01
+#define BT_INTMASK_B2H_IRQ 0x02
+#define BT_INTMASK_BMC_HWRST 0x80
/*
* Minimum size of an IPMI request/response including
@@ -99,23 +101,18 @@ static inline void bt_outb(uint8_t data, uint32_t reg)
lpc_outb(data, bt.base_addr + reg);
}
-static inline bool bt_idle(void)
+static inline void bt_set_h_busy(bool value)
{
- return !(bt_inb(BT_CTRL) & (BT_CTRL_B_BUSY | BT_CTRL_H2B_ATN));
-}
+ uint8_t rval;
-static void bt_setmask(uint8_t mask, uint32_t reg)
-{
- uint8_t tmp;
- tmp = bt_inb(reg);
- bt_outb(tmp | mask, reg);
+ rval = bt_inb(BT_CTRL);
+ if (value != !!(rval & BT_CTRL_H_BUSY))
+ bt_outb(BT_CTRL_H_BUSY, BT_CTRL);
}
-static void bt_clearmask(uint8_t mask, uint32_t reg)
+static inline bool bt_idle(void)
{
- uint8_t tmp;
- tmp = bt_inb(reg);
- bt_outb(tmp & ~mask, reg);
+ return !(bt_inb(BT_CTRL) & (BT_CTRL_B_BUSY | BT_CTRL_H2B_ATN));
}
static inline void bt_set_state(enum bt_states next_state)
@@ -156,7 +153,18 @@ static int bt_add_ipmi_msg(struct ipmi_msg *ipmi_msg)
static void bt_reset_interface(void)
{
- bt_setmask(BT_INTMASK_BMC_HWRST, BT_INTMASK);
+ bt_outb(BT_INTMASK_BMC_HWRST, BT_INTMASK);
+ bt_set_state(BT_STATE_B_BUSY);
+}
+
+static void bt_init_interface(void)
+{
+ /* Clear interrupt condition & enable irq */
+ bt_outb(BT_INTMASK_B2H_IRQ | BT_INTMASK_B2H_IRQEN, BT_INTMASK);
+
+ /* Take care of a stable H_BUSY if any */
+ bt_set_h_busy(false);
+
bt_set_state(BT_STATE_B_BUSY);
}
@@ -183,7 +191,7 @@ static bool bt_try_send_msg(void)
}
/* Send the message */
- bt_setmask(BT_CTRL_CLR_WR_PTR, BT_CTRL);
+ bt_outb(BT_CTRL_CLR_WR_PTR, BT_CTRL);
/* Byte 1 - Length */
bt_outb(ipmi_msg->req_size + BT_MIN_REQ_LEN, BT_HOST2BMC);
@@ -201,7 +209,7 @@ static bool bt_try_send_msg(void)
for (i = 0; i < ipmi_msg->req_size; i++)
bt_outb(ipmi_msg->data[i], BT_HOST2BMC);
- bt_setmask(BT_CTRL_H2B_ATN, BT_CTRL);
+ bt_outb(BT_CTRL_H2B_ATN, BT_CTRL);
bt_set_state(BT_STATE_RESP_WAIT);
unlock(&bt.lock);
@@ -210,10 +218,8 @@ static bool bt_try_send_msg(void)
static void bt_flush_msg(void)
{
- bt_setmask(BT_CTRL_H_BUSY, BT_CTRL);
- bt_clearmask(BT_CTRL_B2H_ATN, BT_CTRL);
- bt_setmask(BT_CTRL_CLR_RD_PTR, BT_CTRL);
- bt_clearmask(BT_CTRL_H_BUSY, BT_CTRL);
+ bt_outb(BT_CTRL_B2H_ATN | BT_CTRL_CLR_RD_PTR, BT_CTRL);
+ bt_set_h_busy(false);
}
static bool bt_get_resp(void)
@@ -231,9 +237,12 @@ static bool bt_get_resp(void)
return true;
}
- bt_setmask(BT_CTRL_H_BUSY, BT_CTRL);
- bt_clearmask(BT_CTRL_B2H_ATN, BT_CTRL);
- bt_setmask(BT_CTRL_CLR_RD_PTR, BT_CTRL);
+ /* Indicate BMC that we are busy */
+ bt_set_h_busy(true);
+
+ /* Clear B2H_ATN and read pointer */
+ bt_outb(BT_CTRL_B2H_ATN, BT_CTRL);
+ bt_outb(BT_CTRL_CLR_RD_PTR, BT_CTRL);
/* Read the response */
/* Byte 1 - Length (includes header size) */
@@ -287,7 +296,7 @@ static bool bt_get_resp(void)
/* Byte 6:N - Data */
for (i = 0; i < resp_len; i++)
ipmi_msg->data[i] = bt_inb(BT_HOST2BMC);
- bt_clearmask(BT_CTRL_H_BUSY, BT_CTRL);
+ bt_set_h_busy(false);
if (cc != IPMI_CC_NO_ERROR)
prerror("BT: Host error 0x%02x receiving BT/IPMI response\n", cc);
@@ -350,6 +359,16 @@ static void bt_poll(void *data __unused)
while(!ret);
}
+void bt_irq(void)
+{
+ uint8_t ireg = bt_inb(BT_INTMASK);
+
+ if (ireg & BT_INTMASK_B2H_IRQ) {
+ bt_outb(BT_INTMASK_B2H_IRQ | BT_INTMASK_B2H_IRQEN, BT_INTMASK);
+ bt_poll(NULL);
+ }
+}
+
/*
* Allocate an ipmi message and bt container and return the ipmi
* message struct. Allocates enough space for the request and response
@@ -424,7 +443,9 @@ void bt_init(void)
return;
}
bt.base_addr = dt_property_get_cell(prop, 1);
- bt_reset_interface();
+ printf("BT: Interface intialized, IO 0x%04x\n", bt.base_addr);
+
+ bt_init_interface();
init_lock(&bt.lock);
/*