coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
ipmi_kcs.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <console/console.h>
4 #include <device/device.h>
5 #include <arch/io.h>
6 #include <timer.h>
7 #include "ipmi_kcs.h"
8 
9 #define IPMI_KCS_STATE(_x) ((_x) >> 6)
10 
11 #define IPMI_KCS_GET_STATUS_ABORT 0x60
12 #define IPMI_KCS_START_WRITE 0x61
13 #define IPMI_KCS_END_WRITE 0x62
14 #define IPMI_KCS_READ_BYTE 0x68
15 
16 #define IPMI_KCS_OBF 0x01
17 #define IPMI_KCS_IBF 0x02
18 #define IPMI_KCS_ATN 0x04
19 
20 #define IPMI_KCS_STATE_IDLE 0x00
21 #define IPMI_KCS_STATE_READ 0x01
22 #define IPMI_KCS_STATE_WRITE 0x02
23 #define IPMI_KCS_STATE_ERROR 0x03
24 
25 #define IPMI_CMD(_x) ((_x) + CONFIG_IPMI_KCS_REGISTER_SPACING)
26 #define IPMI_DATA(_x) ((_x))
27 #define IPMI_STAT(_x) ((_x) + CONFIG_IPMI_KCS_REGISTER_SPACING)
28 
29 static unsigned char ipmi_kcs_status(int port)
30 {
31  unsigned char status = inb(IPMI_STAT(port));
32  if (CONFIG(DEBUG_IPMI))
33  printk(BIOS_SPEW, "%s: 0x%02x\n", __func__, status);
34  return status;
35 }
36 
37 static int wait_ibf_timeout(int port)
38 {
39  if (!wait_ms(CONFIG_IPMI_KCS_TIMEOUT_MS, !(ipmi_kcs_status(port) & IPMI_KCS_IBF))) {
40  printk(BIOS_ERR, "wait_ibf timeout!\n");
41  return 1;
42  } else {
43  return 0;
44  }
45 }
46 
47 static int wait_obf_timeout(int port)
48 {
49  if (!wait_ms(CONFIG_IPMI_KCS_TIMEOUT_MS, (ipmi_kcs_status(port) & IPMI_KCS_OBF))) {
50  printk(BIOS_ERR, "wait_obf timeout!\n");
51  return 1;
52  } else {
53  return 0;
54  }
55 }
56 
57 static int ipmi_kcs_send_data_byte(int port, const unsigned char byte)
58 {
59  unsigned char status;
60 
61  if (CONFIG(DEBUG_IPMI))
62  printk(BIOS_SPEW, "%s: 0x%02x\n", __func__, byte);
63 
64  outb(byte, IPMI_DATA(port));
65 
67  return 1;
68 
69  status = ipmi_kcs_status(port);
70  if ((status & IPMI_KCS_OBF) &&
72  printk(BIOS_ERR, "%s: status %02x\n", __func__, status);
73  return 1;
74  }
75 
77  inb(IPMI_DATA(port));
78  return 0;
79 }
80 
81 static int ipmi_kcs_send_last_data_byte(int port, const unsigned char byte)
82 {
83  unsigned char status;
84 
85  if (CONFIG(DEBUG_IPMI))
86  printk(BIOS_SPEW, "%s: 0x%02x\n", __func__, byte);
87 
89  return 1;
90 
91  status = ipmi_kcs_status(port);
92  if ((status & IPMI_KCS_OBF) &&
94  printk(BIOS_ERR, "%s: status %02x\n", __func__, status);
95  return 1;
96  }
97 
99  inb(IPMI_DATA(port));
100 
101  outb(byte, IPMI_DATA(port));
102  return 0;
103 }
104 
105 static int ipmi_kcs_send_cmd_byte(int port, const unsigned char byte)
106 {
107  if (CONFIG(DEBUG_IPMI))
108  printk(BIOS_SPEW, "%s: 0x%02x\n", __func__, byte);
109 
110  if (wait_ibf_timeout(port))
111  return 1;
112 
114  inb(IPMI_DATA(port));
115  outb(byte, IPMI_CMD(port));
116 
117  if (wait_ibf_timeout(port))
118  return 1;
119 
121  inb(IPMI_DATA(port));
122 
123  return 0;
124 }
125 
126 static int ipmi_kcs_send_message(int port, int netfn, int lun, int cmd,
127  const unsigned char *msg, int len)
128 {
129  int ret;
130 
132  if (ret) {
133  printk(BIOS_ERR, "IPMI START WRITE failed\n");
134  return ret;
135  }
136 
137  ret = ipmi_kcs_send_data_byte(port, (netfn << 2) | (lun & 3));
138  if (ret) {
139  printk(BIOS_ERR, "IPMI NETFN failed\n");
140  return ret;
141  }
142 
143  if (!len) {
145  if (ret) {
146  printk(BIOS_ERR, "IPMI END WRITE failed\n");
147  return ret;
148  }
149 
151  if (ret) {
152  printk(BIOS_ERR, "IPMI BYTE WRITE failed\n");
153  return ret;
154  }
155  } else {
156  ret = ipmi_kcs_send_data_byte(port, cmd);
157  if (ret) {
158  printk(BIOS_ERR, "IPMI CMD failed\n");
159  return ret;
160  }
161 
162  while (len > 1) {
163  ret = ipmi_kcs_send_data_byte(port, *msg++);
164  if (ret) {
165  printk(BIOS_ERR, "IPMI BYTE WRITE failed\n");
166  return ret;
167  }
168  len--;
169  }
170 
172  if (ret) {
173  printk(BIOS_ERR, "IPMI END WRITE failed\n");
174  return ret;
175  }
176 
177  ret = ipmi_kcs_send_last_data_byte(port, *msg);
178  if (ret) {
179  printk(BIOS_ERR, "IPMI BYTE WRITE failed\n");
180  return ret;
181  }
182  }
183 
184  return 0;
185 }
186 
187 static int ipmi_kcs_read_message(int port, unsigned char *msg, int len)
188 {
189  int status, ret = 0;
190 
191  if (wait_ibf_timeout(port))
192  return 1;
193 
194  for (;;) {
195  status = ipmi_kcs_status(port);
196 
197  if (IPMI_KCS_STATE(status) == IPMI_KCS_STATE_IDLE)
198  return ret;
199 
200  if (IPMI_KCS_STATE(status) != IPMI_KCS_STATE_READ) {
201  printk(BIOS_ERR, "%s: wrong state: 0x%02x\n", __func__,
202  status);
203  return -1;
204  }
205 
206  if (wait_obf_timeout(port))
207  return -1;
208 
209  if (msg && (ret < len)) {
210  *msg++ = inb(IPMI_DATA(port));
211  ret++;
212  }
213 
214  if (wait_ibf_timeout(port))
215  return -1;
216 
218  }
219  return ret;
220 }
221 
222 int ipmi_kcs_message(int port, int netfn, int lun, int cmd,
223  const unsigned char *inmsg, int inlen,
224  unsigned char *outmsg, int outlen)
225 {
226  if (ipmi_kcs_send_message(port, netfn, lun, cmd, inmsg, inlen)) {
227  printk(BIOS_ERR, "ipmi_kcs_send_message failed\n");
228  return -1;
229  }
230 
231  return ipmi_kcs_read_message(port, outmsg, outlen);
232 }
#define printk(level,...)
Definition: stdlib.h:16
u8 inb(u16 port)
void outb(u8 val, u16 port)
@ CONFIG
Definition: dsi_common.h:201
port
Definition: i915.h:29
#define wait_ms(timeout_ms, condition)
Definition: timer.h:215
#define IPMI_KCS_STATE_IDLE
Definition: ipmi_kcs.c:20
#define IPMI_KCS_STATE_WRITE
Definition: ipmi_kcs.c:22
#define IPMI_KCS_OBF
Definition: ipmi_kcs.c:16
#define IPMI_STAT(_x)
Definition: ipmi_kcs.c:27
#define IPMI_KCS_STATE_READ
Definition: ipmi_kcs.c:21
#define IPMI_KCS_START_WRITE
Definition: ipmi_kcs.c:12
#define IPMI_KCS_READ_BYTE
Definition: ipmi_kcs.c:14
static int ipmi_kcs_send_last_data_byte(int port, const unsigned char byte)
Definition: ipmi_kcs.c:81
static int ipmi_kcs_send_message(int port, int netfn, int lun, int cmd, const unsigned char *msg, int len)
Definition: ipmi_kcs.c:126
static int ipmi_kcs_send_cmd_byte(int port, const unsigned char byte)
Definition: ipmi_kcs.c:105
static int ipmi_kcs_send_data_byte(int port, const unsigned char byte)
Definition: ipmi_kcs.c:57
#define IPMI_CMD(_x)
Definition: ipmi_kcs.c:25
static int wait_obf_timeout(int port)
Definition: ipmi_kcs.c:47
#define IPMI_KCS_END_WRITE
Definition: ipmi_kcs.c:13
static unsigned char ipmi_kcs_status(int port)
Definition: ipmi_kcs.c:29
#define IPMI_KCS_IBF
Definition: ipmi_kcs.c:17
static int ipmi_kcs_read_message(int port, unsigned char *msg, int len)
Definition: ipmi_kcs.c:187
#define IPMI_DATA(_x)
Definition: ipmi_kcs.c:26
#define IPMI_KCS_STATE(_x)
Definition: ipmi_kcs.c:9
int ipmi_kcs_message(int port, int netfn, int lun, int cmd, const unsigned char *inmsg, int inlen, unsigned char *outmsg, int outlen)
Definition: ipmi_kcs.c:222
static int wait_ibf_timeout(int port)
Definition: ipmi_kcs.c:37
#define BIOS_ERR
BIOS_ERR - System in incomplete state.
Definition: loglevel.h:72
#define BIOS_SPEW
BIOS_SPEW - Excessively verbose output.
Definition: loglevel.h:142