xref: /openbmc/qemu/tests/qtest/ipmi-kcs-test.c (revision c51a3f5d)
1 /*
2  * IPMI KCS test cases, using the local interface.
3  *
4  * Copyright (c) 2012 Corey Minyard <cminyard@mvista.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 
25 #include "qemu/osdep.h"
26 
27 #include "libqtest-single.h"
28 
29 #define IPMI_IRQ        5
30 
31 #define IPMI_KCS_BASE   0xca2
32 
33 #define IPMI_KCS_STATUS_ABORT           0x60
34 #define IPMI_KCS_CMD_WRITE_START        0x61
35 #define IPMI_KCS_CMD_WRITE_END          0x62
36 #define IPMI_KCS_CMD_READ               0x68
37 
38 #define IPMI_KCS_ABORTED_BY_CMD         0x01
39 
40 #define IPMI_KCS_CMDREG_GET_STATE() ((kcs_get_cmdreg() >> 6) & 3)
41 #define IPMI_KCS_STATE_IDLE     0
42 #define IPMI_KCS_STATE_READ     1
43 #define IPMI_KCS_STATE_WRITE    2
44 #define IPMI_KCS_STATE_ERROR    3
45 #define IPMI_KCS_CMDREG_GET_CD()    ((kcs_get_cmdreg() >> 3) & 1)
46 #define IPMI_KCS_CMDREG_GET_ATN()   ((kcs_get_cmdreg() >> 2) & 1)
47 #define IPMI_KCS_CMDREG_GET_IBF()   ((kcs_get_cmdreg() >> 1) & 1)
48 #define IPMI_KCS_CMDREG_GET_OBF()   ((kcs_get_cmdreg() >> 0) & 1)
49 
50 static int kcs_ints_enabled;
51 
52 static uint8_t kcs_get_cmdreg(void)
53 {
54     return inb(IPMI_KCS_BASE + 1);
55 }
56 
57 static void kcs_write_cmdreg(uint8_t val)
58 {
59     outb(IPMI_KCS_BASE + 1, val);
60 }
61 
62 static uint8_t kcs_get_datareg(void)
63 {
64     return inb(IPMI_KCS_BASE);
65 }
66 
67 static void kcs_write_datareg(uint8_t val)
68 {
69     outb(IPMI_KCS_BASE, val);
70 }
71 
72 static void kcs_wait_ibf(void)
73 {
74     unsigned int count = 1000;
75     while (IPMI_KCS_CMDREG_GET_IBF() != 0) {
76         g_assert(--count != 0);
77     }
78 }
79 
80 static void kcs_wait_obf(void)
81 {
82     unsigned int count = 1000;
83     while (IPMI_KCS_CMDREG_GET_OBF() == 0) {
84         --count;
85         g_assert(count != 0);
86     }
87 }
88 
89 static void kcs_clear_obf(void)
90 {
91     if (kcs_ints_enabled) {
92         g_assert(get_irq(IPMI_IRQ));
93     } else {
94         g_assert(!get_irq(IPMI_IRQ));
95     }
96     g_assert(IPMI_KCS_CMDREG_GET_OBF() == 1);
97     kcs_get_datareg();
98     g_assert(IPMI_KCS_CMDREG_GET_OBF() == 0);
99     g_assert(!get_irq(IPMI_IRQ));
100 }
101 
102 static void kcs_check_state(uint8_t state)
103 {
104     g_assert(IPMI_KCS_CMDREG_GET_STATE() == state);
105 }
106 
107 static void kcs_cmd(uint8_t *cmd, unsigned int cmd_len,
108                     uint8_t *rsp, unsigned int *rsp_len)
109 {
110     unsigned int i, j = 0;
111 
112     /* Should be idle */
113     g_assert(kcs_get_cmdreg() == 0);
114 
115     kcs_write_cmdreg(IPMI_KCS_CMD_WRITE_START);
116     kcs_wait_ibf();
117     kcs_check_state(IPMI_KCS_STATE_WRITE);
118     kcs_clear_obf();
119     for (i = 0; i < cmd_len; i++) {
120         kcs_write_datareg(cmd[i]);
121         kcs_wait_ibf();
122         kcs_check_state(IPMI_KCS_STATE_WRITE);
123         kcs_clear_obf();
124     }
125     kcs_write_cmdreg(IPMI_KCS_CMD_WRITE_END);
126     kcs_wait_ibf();
127     kcs_check_state(IPMI_KCS_STATE_WRITE);
128     kcs_clear_obf();
129     kcs_write_datareg(0);
130  next_read_byte:
131     kcs_wait_ibf();
132     switch (IPMI_KCS_CMDREG_GET_STATE()) {
133     case IPMI_KCS_STATE_READ:
134         kcs_wait_obf();
135         g_assert(j < *rsp_len);
136         rsp[j++] = kcs_get_datareg();
137         kcs_write_datareg(IPMI_KCS_CMD_READ);
138         goto next_read_byte;
139         break;
140 
141     case IPMI_KCS_STATE_IDLE:
142         kcs_wait_obf();
143         kcs_get_datareg();
144         break;
145 
146     default:
147         g_assert(0);
148     }
149     *rsp_len = j;
150 }
151 
152 static void kcs_abort(uint8_t *cmd, unsigned int cmd_len,
153                       uint8_t *rsp, unsigned int *rsp_len)
154 {
155     unsigned int i, j = 0;
156     unsigned int retries = 4;
157 
158     /* Should be idle */
159     g_assert(kcs_get_cmdreg() == 0);
160 
161     kcs_write_cmdreg(IPMI_KCS_CMD_WRITE_START);
162     kcs_wait_ibf();
163     kcs_check_state(IPMI_KCS_STATE_WRITE);
164     kcs_clear_obf();
165     for (i = 0; i < cmd_len; i++) {
166         kcs_write_datareg(cmd[i]);
167         kcs_wait_ibf();
168         kcs_check_state(IPMI_KCS_STATE_WRITE);
169         kcs_clear_obf();
170     }
171     kcs_write_cmdreg(IPMI_KCS_CMD_WRITE_END);
172     kcs_wait_ibf();
173     kcs_check_state(IPMI_KCS_STATE_WRITE);
174     kcs_clear_obf();
175     kcs_write_datareg(0);
176     kcs_wait_ibf();
177     switch (IPMI_KCS_CMDREG_GET_STATE()) {
178     case IPMI_KCS_STATE_READ:
179         kcs_wait_obf();
180         g_assert(j < *rsp_len);
181         rsp[j++] = kcs_get_datareg();
182         kcs_write_datareg(IPMI_KCS_CMD_READ);
183         break;
184 
185     default:
186         g_assert(0);
187     }
188 
189     /* Start the abort here */
190  retry_abort:
191     g_assert(retries > 0);
192 
193     kcs_wait_ibf();
194     kcs_write_cmdreg(IPMI_KCS_STATUS_ABORT);
195     kcs_wait_ibf();
196     kcs_clear_obf();
197     kcs_write_datareg(0);
198     kcs_wait_ibf();
199     if (IPMI_KCS_CMDREG_GET_STATE() != IPMI_KCS_STATE_READ) {
200         retries--;
201         goto retry_abort;
202     }
203     kcs_wait_obf();
204     rsp[0] = kcs_get_datareg();
205     kcs_write_datareg(IPMI_KCS_CMD_READ);
206     kcs_wait_ibf();
207     if (IPMI_KCS_CMDREG_GET_STATE() != IPMI_KCS_STATE_IDLE) {
208         retries--;
209         goto retry_abort;
210     }
211     kcs_wait_obf();
212     kcs_clear_obf();
213 
214     *rsp_len = j;
215 }
216 
217 
218 static uint8_t get_dev_id_cmd[] = { 0x18, 0x01 };
219 static uint8_t get_dev_id_rsp[] = { 0x1c, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00,
220                                     0x02, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00 };
221 
222 /*
223  * Send a get_device_id to do a basic test.
224  */
225 static void test_kcs_base(void)
226 {
227     uint8_t rsp[20];
228     unsigned int rsplen = sizeof(rsp);
229 
230     kcs_cmd(get_dev_id_cmd, sizeof(get_dev_id_cmd), rsp, &rsplen);
231     g_assert(rsplen == sizeof(get_dev_id_rsp));
232     g_assert(memcmp(get_dev_id_rsp, rsp, rsplen) == 0);
233 }
234 
235 /*
236  * Abort a kcs operation while reading
237  */
238 static void test_kcs_abort(void)
239 {
240     uint8_t rsp[20];
241     unsigned int rsplen = sizeof(rsp);
242 
243     kcs_abort(get_dev_id_cmd, sizeof(get_dev_id_cmd), rsp, &rsplen);
244     g_assert(rsp[0] == IPMI_KCS_ABORTED_BY_CMD);
245 }
246 
247 static uint8_t set_bmc_globals_cmd[] = { 0x18, 0x2e, 0x0f };
248 static uint8_t set_bmc_globals_rsp[] = { 0x1c, 0x2e, 0x00 };
249 
250 /*
251  * Enable interrupts
252  */
253 static void test_enable_irq(void)
254 {
255     uint8_t rsp[20];
256     unsigned int rsplen = sizeof(rsp);
257 
258     kcs_cmd(set_bmc_globals_cmd, sizeof(set_bmc_globals_cmd), rsp, &rsplen);
259     g_assert(rsplen == sizeof(set_bmc_globals_rsp));
260     g_assert(memcmp(set_bmc_globals_rsp, rsp, rsplen) == 0);
261     kcs_ints_enabled = 1;
262 }
263 
264 int main(int argc, char **argv)
265 {
266     char *cmdline;
267     int ret;
268 
269     /* Run the tests */
270     g_test_init(&argc, &argv, NULL);
271 
272     cmdline = g_strdup_printf("-device ipmi-bmc-sim,id=bmc0"
273                               " -device isa-ipmi-kcs,bmc=bmc0");
274     qtest_start(cmdline);
275     g_free(cmdline);
276     qtest_irq_intercept_in(global_qtest, "ioapic");
277     qtest_add_func("/ipmi/local/kcs_base", test_kcs_base);
278     qtest_add_func("/ipmi/local/kcs_abort", test_kcs_abort);
279     qtest_add_func("/ipmi/local/kcs_enable_irq", test_enable_irq);
280     qtest_add_func("/ipmi/local/kcs_base_irq", test_kcs_base);
281     qtest_add_func("/ipmi/local/kcs_abort_irq", test_kcs_abort);
282     ret = g_test_run();
283     qtest_quit(global_qtest);
284 
285     return ret;
286 }
287