blob: 829b2f9ea1ba7a8419b51b3a2bd8985c7bafeb43 [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.
Sven Schnelle7435baa2012-07-08 18:32:23 +020015 */
16
17#include <console/console.h>
18#include <device/device.h>
19#include <arch/io.h>
20#include <string.h>
21#include <delay.h>
22#include "ipmi_kcs.h"
23
24#define IPMI_KCS_STATE(_x) ((_x) >> 6)
25
26#define IPMI_KCS_GET_STATUS_ABORT
27#define IPMI_KCS_START_WRITE 0x61
28#define IPMI_KCS_END_WRITE 0x62
29#define IPMI_KCS_READ_BYTE 0x68
30
31#define IPMI_KCS_OBF 0x01
32#define IPMI_KCS_IBF 0x02
33#define IPMI_KCS_ATN 0x04
34
35#define IPMI_KCS_STATE_IDLE 0x00
36#define IPMI_KCS_STATE_READ 0x01
37#define IPMI_KCS_STATE_WRITE 0x02
38#define IPMI_KCS_STATE_ERROR 0x03
39
40#define IPMI_CMD(_x) ((_x) + 1)
41#define IPMI_DATA(_x) ((_x))
42#define IPMI_STAT(_x) ((_x) + 1)
43
44static unsigned char ipmi_kcs_status(int port)
45{
46 unsigned char status = inb(IPMI_STAT(port));
47 printk(BIOS_DEBUG, "%s: 0x%02x\n", __func__, status);
48 return status;
49}
50
51static int wait_ibf_timeout(int port)
52{
53 int timeout = 1000;
54 do {
55 if (!(ipmi_kcs_status(port) & IPMI_KCS_IBF))
56 return 0;
57 udelay(100);
58 } while(timeout--);
59 printk(BIOS_ERR, "wait_ibf timeout!\n");
60 return timeout;
61}
62
63static int wait_obf_timeout(int port)
64{
65 int timeout = 1000;
66 do {
67 if ((ipmi_kcs_status(port) & IPMI_KCS_OBF))
68 return 0;
69 udelay(100);
70 } while(timeout--);
71
72 printk(BIOS_ERR, "wait_obf timeout!\n");
73 return timeout;
74}
75
76
77static int ipmi_kcs_send_data_byte(int port, const unsigned char byte)
78{
79 unsigned char status;
80
81 printk(BIOS_DEBUG, "%s: %02x\n", __func__, byte);
82
83 outb(byte, IPMI_DATA(port));
84
85 if (wait_ibf_timeout(port))
86 return 1;
87
88 status = ipmi_kcs_status(port);
89 if ((status & IPMI_KCS_OBF) &&
90 IPMI_KCS_STATE(status) != IPMI_KCS_STATE_WRITE) {
91 printk(BIOS_ERR, "%s: status %02x\n", __func__, status);
92 return 1;
93 }
94
95 if (ipmi_kcs_status(port) & IPMI_KCS_OBF)
96 inb(IPMI_DATA(port));
97 return 0;
98}
99
100static int ipmi_kcs_send_last_data_byte(int port, const unsigned char byte)
101{
102 unsigned char status;
103
104 printk(BIOS_DEBUG, "%s: %02x\n", __func__, byte);
105
106 if (wait_ibf_timeout(port))
107 return 1;
108
109 status = ipmi_kcs_status(port);
110 if ((status & IPMI_KCS_OBF) &&
111 IPMI_KCS_STATE(status) != IPMI_KCS_STATE_WRITE) {
112 printk(BIOS_ERR, "%s: status %02x\n", __func__, status);
113 return 1;
114 }
115
116 if (ipmi_kcs_status(port) & IPMI_KCS_OBF)
117 inb(IPMI_DATA(port));
118
119 outb(byte, IPMI_DATA(port));
120 return 0;
121}
122
123static int ipmi_kcs_send_cmd_byte(int port, const unsigned char byte)
124{
125 printk(BIOS_DEBUG, "%s: 0x%02x\n", __func__, byte);
126
127 if (wait_ibf_timeout(port))
128 return 1;
129
130 if (ipmi_kcs_status(port) & IPMI_KCS_OBF)
131 inb(IPMI_DATA(port));
132 outb(byte, IPMI_CMD(port));
133
134 if (wait_ibf_timeout(port))
135 return 1;
136
137 if (ipmi_kcs_status(port) & IPMI_KCS_OBF)
138 inb(IPMI_DATA(port));
139
140 return 0;
141}
142
143static int ipmi_kcs_send_message(int port, int netfn, int lun, int cmd,
144 const unsigned char *msg, int len)
145{
146 int ret;
147
148 if ((ret = ipmi_kcs_send_cmd_byte(port, IPMI_KCS_START_WRITE))) {
149 printk(BIOS_ERR, "IPMI START WRITE failed\n");
150 return ret;
151 }
152
153 if ((ret = ipmi_kcs_send_data_byte(port, (netfn << 2) | (lun & 3)))) {
154 printk(BIOS_ERR, "IPMI NETFN failed\n");
155 return ret;
156 }
157
158 if ((ret = ipmi_kcs_send_data_byte(port, cmd))) {
159 printk(BIOS_ERR, "IPMI CMD failed\n");
160 return ret;
161 }
162
163 while(len-- > 1) {
164 if ((ret = ipmi_kcs_send_data_byte(port, *msg++))) {
165 printk(BIOS_ERR, "IPMI BYTE WRITE failed\n");
166 return ret;
167 }
168 }
169
170 if ((ret = ipmi_kcs_send_cmd_byte(port, IPMI_KCS_END_WRITE))) {
171 printk(BIOS_ERR, "IPMI END WRITE failed\n");
172 return ret;
173 }
174
175 if ((ret = ipmi_kcs_send_last_data_byte(port, *msg++))) {
176 printk(BIOS_ERR, "IPMI BYTE WRITE failed\n");
177 return ret;
178 }
179 return 0;
180}
181
182static int ipmi_kcs_read_message(int port, unsigned char *msg, int len)
183{
184 int status, ret = 0;
185
186 if (!msg)
187 return 0;
188
189 if (wait_ibf_timeout(port))
190 return 1;
191
192 for(;;) {
193 status = ipmi_kcs_status(port);
194
195 if (IPMI_KCS_STATE(status) == IPMI_KCS_STATE_IDLE)
196 return ret;
197
198 if (IPMI_KCS_STATE(status) != IPMI_KCS_STATE_READ) {
199 printk(BIOS_ERR, "%s: wrong state: 0x%02x\n", __func__, status);
200 return -1;
201 }
202
203 if (wait_obf_timeout(port))
204 return -1;
205
206 *msg++ = inb(IPMI_DATA(port));
207 ret++;
208
209 if (wait_ibf_timeout(port))
210 return -1;
211
212 outb(IPMI_KCS_READ_BYTE, IPMI_DATA(port));
213 }
214 return ret;
215}
216
217int ipmi_kcs_message(int port, int netfn, int lun, int cmd,
218 const unsigned char *inmsg, int inlen,
219 unsigned char *outmsg, int outlen)
220{
221 if (ipmi_kcs_send_message(port, netfn, lun, cmd, inmsg, inlen)) {
222 printk(BIOS_ERR, "ipmi_kcs_send_message failed\n");
223 return -1;
224 }
225
226 return ipmi_kcs_read_message(port, outmsg, outlen);
227}