blob: 9be14331f2e638ec2164b447d46d1050cf75acff [file] [log] [blame]
Sven Schnelle7435baa2012-07-08 18:32:23 +02001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2012 Sven Schnelle <svens@stackframe.org>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; version 2 of
9 * the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
19 * MA 02110-1301 USA
20 */
21
22#include <console/console.h>
23#include <device/device.h>
24#include <arch/io.h>
25#include <string.h>
26#include <delay.h>
27#include "ipmi_kcs.h"
28
29#define IPMI_KCS_STATE(_x) ((_x) >> 6)
30
31#define IPMI_KCS_GET_STATUS_ABORT
32#define IPMI_KCS_START_WRITE 0x61
33#define IPMI_KCS_END_WRITE 0x62
34#define IPMI_KCS_READ_BYTE 0x68
35
36#define IPMI_KCS_OBF 0x01
37#define IPMI_KCS_IBF 0x02
38#define IPMI_KCS_ATN 0x04
39
40#define IPMI_KCS_STATE_IDLE 0x00
41#define IPMI_KCS_STATE_READ 0x01
42#define IPMI_KCS_STATE_WRITE 0x02
43#define IPMI_KCS_STATE_ERROR 0x03
44
45#define IPMI_CMD(_x) ((_x) + 1)
46#define IPMI_DATA(_x) ((_x))
47#define IPMI_STAT(_x) ((_x) + 1)
48
49static unsigned char ipmi_kcs_status(int port)
50{
51 unsigned char status = inb(IPMI_STAT(port));
52 printk(BIOS_DEBUG, "%s: 0x%02x\n", __func__, status);
53 return status;
54}
55
56static int wait_ibf_timeout(int port)
57{
58 int timeout = 1000;
59 do {
60 if (!(ipmi_kcs_status(port) & IPMI_KCS_IBF))
61 return 0;
62 udelay(100);
63 } while(timeout--);
64 printk(BIOS_ERR, "wait_ibf timeout!\n");
65 return timeout;
66}
67
68static int wait_obf_timeout(int port)
69{
70 int timeout = 1000;
71 do {
72 if ((ipmi_kcs_status(port) & IPMI_KCS_OBF))
73 return 0;
74 udelay(100);
75 } while(timeout--);
76
77 printk(BIOS_ERR, "wait_obf timeout!\n");
78 return timeout;
79}
80
81
82static int ipmi_kcs_send_data_byte(int port, const unsigned char byte)
83{
84 unsigned char status;
85
86 printk(BIOS_DEBUG, "%s: %02x\n", __func__, byte);
87
88 outb(byte, IPMI_DATA(port));
89
90 if (wait_ibf_timeout(port))
91 return 1;
92
93 status = ipmi_kcs_status(port);
94 if ((status & IPMI_KCS_OBF) &&
95 IPMI_KCS_STATE(status) != IPMI_KCS_STATE_WRITE) {
96 printk(BIOS_ERR, "%s: status %02x\n", __func__, status);
97 return 1;
98 }
99
100 if (ipmi_kcs_status(port) & IPMI_KCS_OBF)
101 inb(IPMI_DATA(port));
102 return 0;
103}
104
105static int ipmi_kcs_send_last_data_byte(int port, const unsigned char byte)
106{
107 unsigned char status;
108
109 printk(BIOS_DEBUG, "%s: %02x\n", __func__, byte);
110
111 if (wait_ibf_timeout(port))
112 return 1;
113
114 status = ipmi_kcs_status(port);
115 if ((status & IPMI_KCS_OBF) &&
116 IPMI_KCS_STATE(status) != IPMI_KCS_STATE_WRITE) {
117 printk(BIOS_ERR, "%s: status %02x\n", __func__, status);
118 return 1;
119 }
120
121 if (ipmi_kcs_status(port) & IPMI_KCS_OBF)
122 inb(IPMI_DATA(port));
123
124 outb(byte, IPMI_DATA(port));
125 return 0;
126}
127
128static int ipmi_kcs_send_cmd_byte(int port, const unsigned char byte)
129{
130 printk(BIOS_DEBUG, "%s: 0x%02x\n", __func__, byte);
131
132 if (wait_ibf_timeout(port))
133 return 1;
134
135 if (ipmi_kcs_status(port) & IPMI_KCS_OBF)
136 inb(IPMI_DATA(port));
137 outb(byte, IPMI_CMD(port));
138
139 if (wait_ibf_timeout(port))
140 return 1;
141
142 if (ipmi_kcs_status(port) & IPMI_KCS_OBF)
143 inb(IPMI_DATA(port));
144
145 return 0;
146}
147
148static int ipmi_kcs_send_message(int port, int netfn, int lun, int cmd,
149 const unsigned char *msg, int len)
150{
151 int ret;
152
153 if ((ret = ipmi_kcs_send_cmd_byte(port, IPMI_KCS_START_WRITE))) {
154 printk(BIOS_ERR, "IPMI START WRITE failed\n");
155 return ret;
156 }
157
158 if ((ret = ipmi_kcs_send_data_byte(port, (netfn << 2) | (lun & 3)))) {
159 printk(BIOS_ERR, "IPMI NETFN failed\n");
160 return ret;
161 }
162
163 if ((ret = ipmi_kcs_send_data_byte(port, cmd))) {
164 printk(BIOS_ERR, "IPMI CMD failed\n");
165 return ret;
166 }
167
168 while(len-- > 1) {
169 if ((ret = ipmi_kcs_send_data_byte(port, *msg++))) {
170 printk(BIOS_ERR, "IPMI BYTE WRITE failed\n");
171 return ret;
172 }
173 }
174
175 if ((ret = ipmi_kcs_send_cmd_byte(port, IPMI_KCS_END_WRITE))) {
176 printk(BIOS_ERR, "IPMI END WRITE failed\n");
177 return ret;
178 }
179
180 if ((ret = ipmi_kcs_send_last_data_byte(port, *msg++))) {
181 printk(BIOS_ERR, "IPMI BYTE WRITE failed\n");
182 return ret;
183 }
184 return 0;
185}
186
187static int ipmi_kcs_read_message(int port, unsigned char *msg, int len)
188{
189 int status, ret = 0;
190
191 if (!msg)
192 return 0;
193
194 if (wait_ibf_timeout(port))
195 return 1;
196
197 for(;;) {
198 status = ipmi_kcs_status(port);
199
200 if (IPMI_KCS_STATE(status) == IPMI_KCS_STATE_IDLE)
201 return ret;
202
203 if (IPMI_KCS_STATE(status) != IPMI_KCS_STATE_READ) {
204 printk(BIOS_ERR, "%s: wrong state: 0x%02x\n", __func__, status);
205 return -1;
206 }
207
208 if (wait_obf_timeout(port))
209 return -1;
210
211 *msg++ = inb(IPMI_DATA(port));
212 ret++;
213
214 if (wait_ibf_timeout(port))
215 return -1;
216
217 outb(IPMI_KCS_READ_BYTE, IPMI_DATA(port));
218 }
219 return ret;
220}
221
222int 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}