1*68857fbeSCédric Le Goater /*
2*68857fbeSCédric Le Goater * ASPEED iBT Device
3*68857fbeSCédric Le Goater *
4*68857fbeSCédric Le Goater * Copyright (c) 2016-2021 Cédric Le Goater, IBM Corporation.
5*68857fbeSCédric Le Goater *
6*68857fbeSCédric Le Goater * This code is licensed under the GPL version 2 or later. See
7*68857fbeSCédric Le Goater * the COPYING file in the top-level directory.
8*68857fbeSCédric Le Goater */
9*68857fbeSCédric Le Goater
10*68857fbeSCédric Le Goater #include "qemu/osdep.h"
11*68857fbeSCédric Le Goater #include "hw/sysbus.h"
12*68857fbeSCédric Le Goater #include "sysemu/qtest.h"
13*68857fbeSCédric Le Goater #include "sysemu/sysemu.h"
14*68857fbeSCédric Le Goater #include "qemu/log.h"
15*68857fbeSCédric Le Goater #include "qapi/error.h"
16*68857fbeSCédric Le Goater #include "qemu/error-report.h"
17*68857fbeSCédric Le Goater #include "hw/irq.h"
18*68857fbeSCédric Le Goater #include "hw/qdev-properties.h"
19*68857fbeSCédric Le Goater #include "hw/qdev-properties-system.h"
20*68857fbeSCédric Le Goater #include "migration/vmstate.h"
21*68857fbeSCédric Le Goater #include "hw/misc/aspeed_ibt.h"
22*68857fbeSCédric Le Goater #include "trace.h"
23*68857fbeSCédric Le Goater
24*68857fbeSCédric Le Goater #define BT_IO_REGION_SIZE 0x1C
25*68857fbeSCédric Le Goater
26*68857fbeSCédric Le Goater #define TO_REG(o) (o >> 2)
27*68857fbeSCédric Le Goater
28*68857fbeSCédric Le Goater #define BT_CR0 0x0 /* iBT config */
29*68857fbeSCédric Le Goater #define BT_CR0_IO_BASE 16
30*68857fbeSCédric Le Goater #define BT_CR0_IRQ 12
31*68857fbeSCédric Le Goater #define BT_CR0_EN_CLR_SLV_RDP 0x8
32*68857fbeSCédric Le Goater #define BT_CR0_EN_CLR_SLV_WRP 0x4
33*68857fbeSCédric Le Goater #define BT_CR0_ENABLE_IBT 0x1
34*68857fbeSCédric Le Goater #define BT_CR1 0x4 /* interrupt enable */
35*68857fbeSCédric Le Goater #define BT_CR1_IRQ_H2B 0x01
36*68857fbeSCédric Le Goater #define BT_CR1_IRQ_HBUSY 0x40
37*68857fbeSCédric Le Goater #define BT_CR2 0x8 /* interrupt status */
38*68857fbeSCédric Le Goater #define BT_CR2_IRQ_H2B 0x01
39*68857fbeSCédric Le Goater #define BT_CR2_IRQ_HBUSY 0x40
40*68857fbeSCédric Le Goater #define BT_CR3 0xc /* unused */
41*68857fbeSCédric Le Goater #define BT_CTRL 0x10
42*68857fbeSCédric Le Goater #define BT_CTRL_B_BUSY 0x80
43*68857fbeSCédric Le Goater #define BT_CTRL_H_BUSY 0x40
44*68857fbeSCédric Le Goater #define BT_CTRL_OEM0 0x20
45*68857fbeSCédric Le Goater #define BT_CTRL_SMS_ATN 0x10
46*68857fbeSCédric Le Goater #define BT_CTRL_B2H_ATN 0x08
47*68857fbeSCédric Le Goater #define BT_CTRL_H2B_ATN 0x04
48*68857fbeSCédric Le Goater #define BT_CTRL_CLR_RD_PTR 0x02
49*68857fbeSCédric Le Goater #define BT_CTRL_CLR_WR_PTR 0x01
50*68857fbeSCédric Le Goater #define BT_BMC2HOST 0x14
51*68857fbeSCédric Le Goater #define BT_INTMASK 0x18
52*68857fbeSCédric Le Goater #define BT_INTMASK_B2H_IRQEN 0x01
53*68857fbeSCédric Le Goater #define BT_INTMASK_B2H_IRQ 0x02
54*68857fbeSCédric Le Goater #define BT_INTMASK_BMC_HWRST 0x80
55*68857fbeSCédric Le Goater
56*68857fbeSCédric Le Goater /*
57*68857fbeSCédric Le Goater * VM IPMI defines
58*68857fbeSCédric Le Goater */
59*68857fbeSCédric Le Goater #define VM_MSG_CHAR 0xA0 /* Marks end of message */
60*68857fbeSCédric Le Goater #define VM_CMD_CHAR 0xA1 /* Marks end of a command */
61*68857fbeSCédric Le Goater #define VM_ESCAPE_CHAR 0xAA /* Set bit 4 from the next byte to 0 */
62*68857fbeSCédric Le Goater
63*68857fbeSCédric Le Goater #define VM_PROTOCOL_VERSION 1
64*68857fbeSCédric Le Goater #define VM_CMD_VERSION 0xff /* A version number byte follows */
65*68857fbeSCédric Le Goater #define VM_CMD_NOATTN 0x00
66*68857fbeSCédric Le Goater #define VM_CMD_ATTN 0x01
67*68857fbeSCédric Le Goater #define VM_CMD_ATTN_IRQ 0x02
68*68857fbeSCédric Le Goater #define VM_CMD_POWEROFF 0x03
69*68857fbeSCédric Le Goater #define VM_CMD_RESET 0x04
70*68857fbeSCédric Le Goater #define VM_CMD_ENABLE_IRQ 0x05 /* Enable/disable the messaging irq */
71*68857fbeSCédric Le Goater #define VM_CMD_DISABLE_IRQ 0x06
72*68857fbeSCédric Le Goater #define VM_CMD_SEND_NMI 0x07
73*68857fbeSCédric Le Goater #define VM_CMD_CAPABILITIES 0x08
74*68857fbeSCédric Le Goater #define VM_CAPABILITIES_POWER 0x01
75*68857fbeSCédric Le Goater #define VM_CAPABILITIES_RESET 0x02
76*68857fbeSCédric Le Goater #define VM_CAPABILITIES_IRQ 0x04
77*68857fbeSCédric Le Goater #define VM_CAPABILITIES_NMI 0x08
78*68857fbeSCédric Le Goater #define VM_CAPABILITIES_ATTN 0x10
79*68857fbeSCédric Le Goater #define VM_CAPABILITIES_GRACEFUL_SHUTDOWN 0x20
80*68857fbeSCédric Le Goater #define VM_CMD_GRACEFUL_SHUTDOWN 0x09
81*68857fbeSCédric Le Goater
82*68857fbeSCédric Le Goater /*
83*68857fbeSCédric Le Goater * These routines are inspired by the 'ipmi-bmc-extern' model and by
84*68857fbeSCédric Le Goater * the lanserv simulator of OpenIPMI. See :
85*68857fbeSCédric Le Goater * https://github.com/cminyard/openipmi/blob/master/lanserv/serial_ipmi.c
86*68857fbeSCédric Le Goater */
ipmb_checksum(const unsigned char * data,int size,unsigned char start)87*68857fbeSCédric Le Goater static unsigned char ipmb_checksum(const unsigned char *data, int size,
88*68857fbeSCédric Le Goater unsigned char start)
89*68857fbeSCédric Le Goater {
90*68857fbeSCédric Le Goater unsigned char csum = start;
91*68857fbeSCédric Le Goater
92*68857fbeSCédric Le Goater for (; size > 0; size--, data++) {
93*68857fbeSCédric Le Goater csum += *data;
94*68857fbeSCédric Le Goater }
95*68857fbeSCédric Le Goater return csum;
96*68857fbeSCédric Le Goater }
97*68857fbeSCédric Le Goater
vm_add_char(unsigned char ch,unsigned char * c,unsigned int * pos)98*68857fbeSCédric Le Goater static void vm_add_char(unsigned char ch, unsigned char *c, unsigned int *pos)
99*68857fbeSCédric Le Goater {
100*68857fbeSCédric Le Goater switch (ch) {
101*68857fbeSCédric Le Goater case VM_MSG_CHAR:
102*68857fbeSCédric Le Goater case VM_CMD_CHAR:
103*68857fbeSCédric Le Goater case VM_ESCAPE_CHAR:
104*68857fbeSCédric Le Goater c[(*pos)++] = VM_ESCAPE_CHAR;
105*68857fbeSCédric Le Goater c[(*pos)++] = ch | 0x10;
106*68857fbeSCédric Le Goater break;
107*68857fbeSCédric Le Goater
108*68857fbeSCédric Le Goater default:
109*68857fbeSCédric Le Goater c[(*pos)++] = ch;
110*68857fbeSCédric Le Goater }
111*68857fbeSCédric Le Goater }
112*68857fbeSCédric Le Goater
aspeed_ibt_dump_msg(const char * func,unsigned char * msg,unsigned int len)113*68857fbeSCédric Le Goater static void aspeed_ibt_dump_msg(const char *func, unsigned char *msg,
114*68857fbeSCédric Le Goater unsigned int len)
115*68857fbeSCédric Le Goater {
116*68857fbeSCédric Le Goater if (trace_event_get_state_backends(TRACE_ASPEED_IBT_CHR_DUMP_MSG)) {
117*68857fbeSCédric Le Goater int size = len * 3 + 1;
118*68857fbeSCédric Le Goater g_autofree char *tmp = g_malloc(size);
119*68857fbeSCédric Le Goater int i, n = 0;
120*68857fbeSCédric Le Goater
121*68857fbeSCédric Le Goater for (i = 0; i < len; i++) {
122*68857fbeSCédric Le Goater n += snprintf(tmp + n, size - n, "%02x:", msg[i]);
123*68857fbeSCédric Le Goater }
124*68857fbeSCédric Le Goater tmp[size - 1] = 0;
125*68857fbeSCédric Le Goater
126*68857fbeSCédric Le Goater trace_aspeed_ibt_chr_dump_msg(func, tmp, len);
127*68857fbeSCédric Le Goater }
128*68857fbeSCédric Le Goater }
129*68857fbeSCédric Le Goater
aspeed_ibt_chr_write(AspeedIBTState * ibt,const uint8_t * buf,int len)130*68857fbeSCédric Le Goater static void aspeed_ibt_chr_write(AspeedIBTState *ibt, const uint8_t *buf,
131*68857fbeSCédric Le Goater int len)
132*68857fbeSCédric Le Goater {
133*68857fbeSCédric Le Goater int i;
134*68857fbeSCédric Le Goater
135*68857fbeSCédric Le Goater if (!qemu_chr_fe_get_driver(&ibt->chr)) {
136*68857fbeSCédric Le Goater return;
137*68857fbeSCédric Le Goater }
138*68857fbeSCédric Le Goater
139*68857fbeSCédric Le Goater aspeed_ibt_dump_msg(__func__, ibt->recv_msg, ibt->recv_msg_len);
140*68857fbeSCédric Le Goater
141*68857fbeSCédric Le Goater for (i = 0; i < len; i++) {
142*68857fbeSCédric Le Goater qemu_chr_fe_write(&ibt->chr, &buf[i], 1);
143*68857fbeSCédric Le Goater }
144*68857fbeSCédric Le Goater }
145*68857fbeSCédric Le Goater
vm_send(AspeedIBTState * ibt)146*68857fbeSCédric Le Goater static void vm_send(AspeedIBTState *ibt)
147*68857fbeSCédric Le Goater {
148*68857fbeSCédric Le Goater unsigned int i;
149*68857fbeSCédric Le Goater unsigned int len = 0;
150*68857fbeSCédric Le Goater g_autofree unsigned char *c = g_malloc((ibt->send_msg_len + 7) * 2);
151*68857fbeSCédric Le Goater uint8_t netfn;
152*68857fbeSCédric Le Goater
153*68857fbeSCédric Le Goater /*
154*68857fbeSCédric Le Goater * The VM IPMI message format does not follow the IPMI BT
155*68857fbeSCédric Le Goater * interface format. The sequence and the netfn bytes need to be
156*68857fbeSCédric Le Goater * swapped.
157*68857fbeSCédric Le Goater */
158*68857fbeSCédric Le Goater netfn = ibt->send_msg[1];
159*68857fbeSCédric Le Goater ibt->send_msg[1] = ibt->send_msg[2];
160*68857fbeSCédric Le Goater ibt->send_msg[2] = netfn;
161*68857fbeSCédric Le Goater
162*68857fbeSCédric Le Goater /* No length byte in the VM IPMI message format. trim it */
163*68857fbeSCédric Le Goater for (i = 1; i < ibt->send_msg_len; i++) {
164*68857fbeSCédric Le Goater vm_add_char(ibt->send_msg[i], c, &len);
165*68857fbeSCédric Le Goater }
166*68857fbeSCédric Le Goater
167*68857fbeSCédric Le Goater vm_add_char(-ipmb_checksum(&ibt->send_msg[1], ibt->send_msg_len - 1, 0),
168*68857fbeSCédric Le Goater c, &len);
169*68857fbeSCédric Le Goater c[len++] = VM_MSG_CHAR;
170*68857fbeSCédric Le Goater
171*68857fbeSCédric Le Goater aspeed_ibt_chr_write(ibt, c, len);
172*68857fbeSCédric Le Goater }
173*68857fbeSCédric Le Goater
aspeed_ibt_update_irq(AspeedIBTState * ibt)174*68857fbeSCédric Le Goater static void aspeed_ibt_update_irq(AspeedIBTState *ibt)
175*68857fbeSCédric Le Goater {
176*68857fbeSCédric Le Goater bool raise = false;
177*68857fbeSCédric Le Goater
178*68857fbeSCédric Le Goater /* H2B rising */
179*68857fbeSCédric Le Goater if ((ibt->regs[TO_REG(BT_CTRL)] & BT_CTRL_H2B_ATN) &&
180*68857fbeSCédric Le Goater ((ibt->regs[TO_REG(BT_CR1)] & BT_CR1_IRQ_H2B) == BT_CR1_IRQ_H2B)) {
181*68857fbeSCédric Le Goater ibt->regs[TO_REG(BT_CR2)] |= BT_CR2_IRQ_H2B;
182*68857fbeSCédric Le Goater
183*68857fbeSCédric Le Goater /*
184*68857fbeSCédric Le Goater * Also flag the fact that we are waiting for the guest/driver
185*68857fbeSCédric Le Goater * to read a received message
186*68857fbeSCédric Le Goater */
187*68857fbeSCédric Le Goater ibt->recv_waiting = true;
188*68857fbeSCédric Le Goater raise = true;
189*68857fbeSCédric Le Goater }
190*68857fbeSCédric Le Goater
191*68857fbeSCédric Le Goater /* H_BUSY falling (not supported) */
192*68857fbeSCédric Le Goater if ((ibt->regs[TO_REG(BT_CTRL)] & BT_CTRL_H_BUSY) &&
193*68857fbeSCédric Le Goater ((ibt->regs[TO_REG(BT_CR1)] & BT_CR1_IRQ_HBUSY) == BT_CR1_IRQ_HBUSY)) {
194*68857fbeSCédric Le Goater ibt->regs[TO_REG(BT_CR2)] |= BT_CR2_IRQ_HBUSY;
195*68857fbeSCédric Le Goater
196*68857fbeSCédric Le Goater raise = true;
197*68857fbeSCédric Le Goater }
198*68857fbeSCédric Le Goater
199*68857fbeSCédric Le Goater if (raise) {
200*68857fbeSCédric Le Goater qemu_irq_raise(ibt->irq);
201*68857fbeSCédric Le Goater }
202*68857fbeSCédric Le Goater }
203*68857fbeSCédric Le Goater
vm_handle_msg(AspeedIBTState * ibt,unsigned char * msg,unsigned int len)204*68857fbeSCédric Le Goater static void vm_handle_msg(AspeedIBTState *ibt, unsigned char *msg,
205*68857fbeSCédric Le Goater unsigned int len)
206*68857fbeSCédric Le Goater {
207*68857fbeSCédric Le Goater uint8_t seq;
208*68857fbeSCédric Le Goater
209*68857fbeSCédric Le Goater aspeed_ibt_dump_msg(__func__, ibt->recv_msg, ibt->recv_msg_len);
210*68857fbeSCédric Le Goater
211*68857fbeSCédric Le Goater if (len < 4) {
212*68857fbeSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, " %s: Message too short\n", __func__);
213*68857fbeSCédric Le Goater return;
214*68857fbeSCédric Le Goater }
215*68857fbeSCédric Le Goater
216*68857fbeSCédric Le Goater if (ipmb_checksum(ibt->recv_msg, ibt->recv_msg_len, 0) != 0) {
217*68857fbeSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, " %s: Message checksum failure\n",
218*68857fbeSCédric Le Goater __func__);
219*68857fbeSCédric Le Goater return;
220*68857fbeSCédric Le Goater }
221*68857fbeSCédric Le Goater
222*68857fbeSCédric Le Goater /* Trim the checksum byte */
223*68857fbeSCédric Le Goater ibt->recv_msg_len--;
224*68857fbeSCédric Le Goater
225*68857fbeSCédric Le Goater /*
226*68857fbeSCédric Le Goater * The VM IPMI message format does not follow the IPMI BT
227*68857fbeSCédric Le Goater * interface format. The sequence and the netfn bytes need to be
228*68857fbeSCédric Le Goater * swapped.
229*68857fbeSCédric Le Goater */
230*68857fbeSCédric Le Goater seq = ibt->recv_msg[0];
231*68857fbeSCédric Le Goater ibt->recv_msg[0] = ibt->recv_msg[1];
232*68857fbeSCédric Le Goater ibt->recv_msg[1] = seq;
233*68857fbeSCédric Le Goater
234*68857fbeSCédric Le Goater aspeed_ibt_update_irq(ibt);
235*68857fbeSCédric Le Goater }
236*68857fbeSCédric Le Goater
237*68857fbeSCédric Le Goater /* TODO: handle commands */
vm_handle_cmd(AspeedIBTState * ibt,unsigned char * msg,unsigned int len)238*68857fbeSCédric Le Goater static void vm_handle_cmd(AspeedIBTState *ibt, unsigned char *msg,
239*68857fbeSCédric Le Goater unsigned int len)
240*68857fbeSCédric Le Goater {
241*68857fbeSCédric Le Goater aspeed_ibt_dump_msg(__func__, ibt->recv_msg, ibt->recv_msg_len);
242*68857fbeSCédric Le Goater
243*68857fbeSCédric Le Goater if (len < 1) {
244*68857fbeSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, " %s: Command too short\n", __func__);
245*68857fbeSCédric Le Goater return;
246*68857fbeSCédric Le Goater }
247*68857fbeSCédric Le Goater
248*68857fbeSCédric Le Goater switch (msg[0]) {
249*68857fbeSCédric Le Goater case VM_CMD_VERSION:
250*68857fbeSCédric Le Goater break;
251*68857fbeSCédric Le Goater
252*68857fbeSCédric Le Goater case VM_CMD_CAPABILITIES:
253*68857fbeSCédric Le Goater if (len < 2) {
254*68857fbeSCédric Le Goater return;
255*68857fbeSCédric Le Goater }
256*68857fbeSCédric Le Goater break;
257*68857fbeSCédric Le Goater
258*68857fbeSCédric Le Goater case VM_CMD_RESET:
259*68857fbeSCédric Le Goater break;
260*68857fbeSCédric Le Goater }
261*68857fbeSCédric Le Goater }
262*68857fbeSCédric Le Goater
vm_handle_char(AspeedIBTState * ibt,unsigned char ch)263*68857fbeSCédric Le Goater static void vm_handle_char(AspeedIBTState *ibt, unsigned char ch)
264*68857fbeSCédric Le Goater {
265*68857fbeSCédric Le Goater unsigned int len = ibt->recv_msg_len;
266*68857fbeSCédric Le Goater
267*68857fbeSCédric Le Goater switch (ch) {
268*68857fbeSCédric Le Goater case VM_MSG_CHAR:
269*68857fbeSCédric Le Goater case VM_CMD_CHAR:
270*68857fbeSCédric Le Goater if (ibt->in_escape) {
271*68857fbeSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, " %s: Message ended in escape\n",
272*68857fbeSCédric Le Goater __func__);
273*68857fbeSCédric Le Goater } else if (ibt->recv_msg_too_many) {
274*68857fbeSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, " %s: Message too long\n", __func__);
275*68857fbeSCédric Le Goater } else if (ibt->recv_msg_len == 0) {
276*68857fbeSCédric Le Goater /* Nothing to do */
277*68857fbeSCédric Le Goater } else if (ch == VM_MSG_CHAR) {
278*68857fbeSCédric Le Goater /* Last byte of message. Signal BMC as the host would do */
279*68857fbeSCédric Le Goater ibt->regs[TO_REG(BT_CTRL)] |= BT_CTRL_H2B_ATN;
280*68857fbeSCédric Le Goater
281*68857fbeSCédric Le Goater vm_handle_msg(ibt, ibt->recv_msg, ibt->recv_msg_len);
282*68857fbeSCédric Le Goater
283*68857fbeSCédric Le Goater /* Message is only handled when read by BMC (!B_BUSY) */
284*68857fbeSCédric Le Goater } else if (ch == VM_CMD_CHAR) {
285*68857fbeSCédric Le Goater vm_handle_cmd(ibt, ibt->recv_msg, ibt->recv_msg_len);
286*68857fbeSCédric Le Goater
287*68857fbeSCédric Le Goater /* Command is now handled. reset receive state */
288*68857fbeSCédric Le Goater ibt->in_escape = 0;
289*68857fbeSCédric Le Goater ibt->recv_msg_len = 0;
290*68857fbeSCédric Le Goater ibt->recv_msg_too_many = 0;
291*68857fbeSCédric Le Goater }
292*68857fbeSCédric Le Goater break;
293*68857fbeSCédric Le Goater
294*68857fbeSCédric Le Goater case VM_ESCAPE_CHAR:
295*68857fbeSCédric Le Goater if (!ibt->recv_msg_too_many) {
296*68857fbeSCédric Le Goater ibt->in_escape = 1;
297*68857fbeSCédric Le Goater }
298*68857fbeSCédric Le Goater break;
299*68857fbeSCédric Le Goater
300*68857fbeSCédric Le Goater default:
301*68857fbeSCédric Le Goater if (ibt->in_escape) {
302*68857fbeSCédric Le Goater ibt->in_escape = 0;
303*68857fbeSCédric Le Goater ch &= ~0x10;
304*68857fbeSCédric Le Goater }
305*68857fbeSCédric Le Goater
306*68857fbeSCédric Le Goater if (!ibt->recv_msg_too_many) {
307*68857fbeSCédric Le Goater if (len >= sizeof(ibt->recv_msg)) {
308*68857fbeSCédric Le Goater ibt->recv_msg_too_many = 1;
309*68857fbeSCédric Le Goater break;
310*68857fbeSCédric Le Goater }
311*68857fbeSCédric Le Goater
312*68857fbeSCédric Le Goater ibt->recv_msg[len] = ch;
313*68857fbeSCédric Le Goater ibt->recv_msg_len++;
314*68857fbeSCédric Le Goater }
315*68857fbeSCédric Le Goater break;
316*68857fbeSCédric Le Goater }
317*68857fbeSCédric Le Goater }
318*68857fbeSCédric Le Goater
vm_connected(AspeedIBTState * ibt)319*68857fbeSCédric Le Goater static void vm_connected(AspeedIBTState *ibt)
320*68857fbeSCédric Le Goater {
321*68857fbeSCédric Le Goater unsigned int len = 0;
322*68857fbeSCédric Le Goater unsigned char c[5];
323*68857fbeSCédric Le Goater
324*68857fbeSCédric Le Goater vm_add_char(VM_CMD_VERSION, c, &len);
325*68857fbeSCédric Le Goater vm_add_char(VM_PROTOCOL_VERSION, c, &len);
326*68857fbeSCédric Le Goater c[len++] = VM_CMD_CHAR;
327*68857fbeSCédric Le Goater
328*68857fbeSCédric Le Goater aspeed_ibt_chr_write(ibt, c, len);
329*68857fbeSCédric Le Goater }
330*68857fbeSCédric Le Goater
aspeed_ibt_chr_event(void * opaque,QEMUChrEvent event)331*68857fbeSCédric Le Goater static void aspeed_ibt_chr_event(void *opaque, QEMUChrEvent event)
332*68857fbeSCédric Le Goater {
333*68857fbeSCédric Le Goater AspeedIBTState *ibt = ASPEED_IBT(opaque);
334*68857fbeSCédric Le Goater
335*68857fbeSCédric Le Goater switch (event) {
336*68857fbeSCédric Le Goater case CHR_EVENT_OPENED:
337*68857fbeSCédric Le Goater vm_connected(ibt);
338*68857fbeSCédric Le Goater ibt->connected = true;
339*68857fbeSCédric Le Goater break;
340*68857fbeSCédric Le Goater
341*68857fbeSCédric Le Goater case CHR_EVENT_CLOSED:
342*68857fbeSCédric Le Goater if (!ibt->connected) {
343*68857fbeSCédric Le Goater return;
344*68857fbeSCédric Le Goater }
345*68857fbeSCédric Le Goater ibt->connected = false;
346*68857fbeSCédric Le Goater break;
347*68857fbeSCédric Le Goater case CHR_EVENT_BREAK:
348*68857fbeSCédric Le Goater case CHR_EVENT_MUX_IN:
349*68857fbeSCédric Le Goater case CHR_EVENT_MUX_OUT:
350*68857fbeSCédric Le Goater /* Ignore */
351*68857fbeSCédric Le Goater break;
352*68857fbeSCédric Le Goater }
353*68857fbeSCédric Le Goater trace_aspeed_ibt_chr_event(ibt->connected);
354*68857fbeSCédric Le Goater }
355*68857fbeSCédric Le Goater
aspeed_ibt_chr_can_receive(void * opaque)356*68857fbeSCédric Le Goater static int aspeed_ibt_chr_can_receive(void *opaque)
357*68857fbeSCédric Le Goater {
358*68857fbeSCédric Le Goater AspeedIBTState *ibt = ASPEED_IBT(opaque);
359*68857fbeSCédric Le Goater
360*68857fbeSCédric Le Goater return !ibt->recv_waiting && !(ibt->regs[TO_REG(BT_CTRL)] & BT_CTRL_B_BUSY);
361*68857fbeSCédric Le Goater }
362*68857fbeSCédric Le Goater
aspeed_ibt_chr_receive(void * opaque,const uint8_t * buf,int size)363*68857fbeSCédric Le Goater static void aspeed_ibt_chr_receive(void *opaque, const uint8_t *buf,
364*68857fbeSCédric Le Goater int size)
365*68857fbeSCédric Le Goater {
366*68857fbeSCédric Le Goater AspeedIBTState *ibt = ASPEED_IBT(opaque);
367*68857fbeSCédric Le Goater int i;
368*68857fbeSCédric Le Goater
369*68857fbeSCédric Le Goater if (!ibt->connected) {
370*68857fbeSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, " %s: not connected !?\n", __func__);
371*68857fbeSCédric Le Goater return;
372*68857fbeSCédric Le Goater }
373*68857fbeSCédric Le Goater
374*68857fbeSCédric Le Goater for (i = 0; i < size; i++) {
375*68857fbeSCédric Le Goater vm_handle_char(ibt, buf[i]);
376*68857fbeSCédric Le Goater }
377*68857fbeSCédric Le Goater }
378*68857fbeSCédric Le Goater
aspeed_ibt_write(void * opaque,hwaddr offset,uint64_t data,unsigned size)379*68857fbeSCédric Le Goater static void aspeed_ibt_write(void *opaque, hwaddr offset, uint64_t data,
380*68857fbeSCédric Le Goater unsigned size)
381*68857fbeSCédric Le Goater {
382*68857fbeSCédric Le Goater AspeedIBTState *ibt = ASPEED_IBT(opaque);
383*68857fbeSCédric Le Goater
384*68857fbeSCédric Le Goater trace_aspeed_ibt_write(offset, data);
385*68857fbeSCédric Le Goater
386*68857fbeSCédric Le Goater switch (offset) {
387*68857fbeSCédric Le Goater case BT_CTRL:
388*68857fbeSCédric Le Goater /* CLR_WR_PTR: cleared before a message is written */
389*68857fbeSCédric Le Goater if (data & BT_CTRL_CLR_WR_PTR) {
390*68857fbeSCédric Le Goater memset(ibt->send_msg, 0, sizeof(ibt->send_msg));
391*68857fbeSCédric Le Goater ibt->send_msg_len = 0;
392*68857fbeSCédric Le Goater trace_aspeed_ibt_event("CLR_WR_PTR");
393*68857fbeSCédric Le Goater }
394*68857fbeSCédric Le Goater
395*68857fbeSCédric Le Goater /* CLR_RD_PTR: cleared before a message is read */
396*68857fbeSCédric Le Goater else if (data & BT_CTRL_CLR_RD_PTR) {
397*68857fbeSCédric Le Goater ibt->recv_msg_index = -1;
398*68857fbeSCédric Le Goater trace_aspeed_ibt_event("CLR_RD_PTR");
399*68857fbeSCédric Le Goater }
400*68857fbeSCédric Le Goater
401*68857fbeSCédric Le Goater /*
402*68857fbeSCédric Le Goater * H2B_ATN: raised by host to end message, cleared by BMC
403*68857fbeSCédric Le Goater * before reading message
404*68857fbeSCédric Le Goater */
405*68857fbeSCédric Le Goater else if (data & BT_CTRL_H2B_ATN) {
406*68857fbeSCédric Le Goater ibt->regs[TO_REG(BT_CTRL)] &= ~BT_CTRL_H2B_ATN;
407*68857fbeSCédric Le Goater trace_aspeed_ibt_event("H2B_ATN");
408*68857fbeSCédric Le Goater }
409*68857fbeSCédric Le Goater
410*68857fbeSCédric Le Goater /* B_BUSY: raised and cleared by BMC when message is read */
411*68857fbeSCédric Le Goater else if (data & BT_CTRL_B_BUSY) {
412*68857fbeSCédric Le Goater ibt->regs[TO_REG(BT_CTRL)] ^= BT_CTRL_B_BUSY;
413*68857fbeSCédric Le Goater trace_aspeed_ibt_event("B_BUSY");
414*68857fbeSCédric Le Goater }
415*68857fbeSCédric Le Goater
416*68857fbeSCédric Le Goater /*
417*68857fbeSCédric Le Goater * B2H_ATN: raised by BMC and cleared by host
418*68857fbeSCédric Le Goater *
419*68857fbeSCédric Le Goater * Also simulate the host busy bit which is set while the host
420*68857fbeSCédric Le Goater * is reading the message from the BMC
421*68857fbeSCédric Le Goater */
422*68857fbeSCédric Le Goater else if (data & BT_CTRL_B2H_ATN) {
423*68857fbeSCédric Le Goater trace_aspeed_ibt_event("B2H_ATN");
424*68857fbeSCédric Le Goater ibt->regs[TO_REG(BT_CTRL)] |= (BT_CTRL_B2H_ATN | BT_CTRL_H_BUSY);
425*68857fbeSCédric Le Goater
426*68857fbeSCédric Le Goater vm_send(ibt);
427*68857fbeSCédric Le Goater
428*68857fbeSCédric Le Goater ibt->regs[TO_REG(BT_CTRL)] &= ~(BT_CTRL_B2H_ATN | BT_CTRL_H_BUSY);
429*68857fbeSCédric Le Goater
430*68857fbeSCédric Le Goater /* signal H_BUSY falling but that's a bit useless */
431*68857fbeSCédric Le Goater aspeed_ibt_update_irq(ibt);
432*68857fbeSCédric Le Goater }
433*68857fbeSCédric Le Goater
434*68857fbeSCédric Le Goater /* Anything else is unexpected */
435*68857fbeSCédric Le Goater else {
436*68857fbeSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: unexpected CTRL setting\n",
437*68857fbeSCédric Le Goater __func__);
438*68857fbeSCédric Le Goater }
439*68857fbeSCédric Le Goater
440*68857fbeSCédric Le Goater /* Message was read by BMC. we can reset the receive state */
441*68857fbeSCédric Le Goater if (!(ibt->regs[TO_REG(BT_CTRL)] & BT_CTRL_B_BUSY)) {
442*68857fbeSCédric Le Goater trace_aspeed_ibt_event("B_BUSY cleared");
443*68857fbeSCédric Le Goater ibt->recv_waiting = false;
444*68857fbeSCédric Le Goater ibt->in_escape = 0;
445*68857fbeSCédric Le Goater ibt->recv_msg_len = 0;
446*68857fbeSCédric Le Goater ibt->recv_msg_too_many = 0;
447*68857fbeSCédric Le Goater }
448*68857fbeSCédric Le Goater break;
449*68857fbeSCédric Le Goater
450*68857fbeSCédric Le Goater case BT_BMC2HOST:
451*68857fbeSCédric Le Goater if (ibt->send_msg_len < sizeof(ibt->send_msg)) {
452*68857fbeSCédric Le Goater trace_aspeed_ibt_event("BMC2HOST");
453*68857fbeSCédric Le Goater ibt->send_msg[ibt->send_msg_len++] = data & 0xff;
454*68857fbeSCédric Le Goater }
455*68857fbeSCédric Le Goater break;
456*68857fbeSCédric Le Goater
457*68857fbeSCédric Le Goater case BT_CR0: /* TODO: iBT config */
458*68857fbeSCédric Le Goater case BT_CR1: /* interrupt enable */
459*68857fbeSCédric Le Goater case BT_CR3: /* unused */
460*68857fbeSCédric Le Goater case BT_INTMASK:
461*68857fbeSCédric Le Goater ibt->regs[TO_REG(offset)] = (uint32_t) data;
462*68857fbeSCédric Le Goater break;
463*68857fbeSCédric Le Goater case BT_CR2: /* interrupt status. writing 1 clears. */
464*68857fbeSCédric Le Goater ibt->regs[TO_REG(offset)] ^= (uint32_t) data;
465*68857fbeSCédric Le Goater qemu_irq_lower(ibt->irq);
466*68857fbeSCédric Le Goater break;
467*68857fbeSCédric Le Goater
468*68857fbeSCédric Le Goater default:
469*68857fbeSCédric Le Goater qemu_log_mask(LOG_UNIMP, "%s: not implemented 0x%" HWADDR_PRIx "\n",
470*68857fbeSCédric Le Goater __func__, offset);
471*68857fbeSCédric Le Goater break;
472*68857fbeSCédric Le Goater }
473*68857fbeSCédric Le Goater }
474*68857fbeSCédric Le Goater
aspeed_ibt_read(void * opaque,hwaddr offset,unsigned size)475*68857fbeSCédric Le Goater static uint64_t aspeed_ibt_read(void *opaque, hwaddr offset, unsigned size)
476*68857fbeSCédric Le Goater {
477*68857fbeSCédric Le Goater AspeedIBTState *ibt = ASPEED_IBT(opaque);
478*68857fbeSCédric Le Goater uint64_t val = 0;
479*68857fbeSCédric Le Goater
480*68857fbeSCédric Le Goater switch (offset) {
481*68857fbeSCédric Le Goater case BT_BMC2HOST:
482*68857fbeSCédric Le Goater trace_aspeed_ibt_event("BMC2HOST");
483*68857fbeSCédric Le Goater /*
484*68857fbeSCédric Le Goater * The IPMI BT interface requires the first byte to be the
485*68857fbeSCédric Le Goater * length of the message
486*68857fbeSCédric Le Goater */
487*68857fbeSCédric Le Goater if (ibt->recv_msg_index == -1) {
488*68857fbeSCédric Le Goater val = ibt->recv_msg_len;
489*68857fbeSCédric Le Goater ibt->recv_msg_index++;
490*68857fbeSCédric Le Goater } else if (ibt->recv_msg_index < ibt->recv_msg_len) {
491*68857fbeSCédric Le Goater val = ibt->recv_msg[ibt->recv_msg_index++];
492*68857fbeSCédric Le Goater }
493*68857fbeSCédric Le Goater break;
494*68857fbeSCédric Le Goater
495*68857fbeSCédric Le Goater case BT_CR0:
496*68857fbeSCédric Le Goater case BT_CR1:
497*68857fbeSCédric Le Goater case BT_CR2:
498*68857fbeSCédric Le Goater case BT_CR3:
499*68857fbeSCédric Le Goater case BT_CTRL:
500*68857fbeSCédric Le Goater case BT_INTMASK:
501*68857fbeSCédric Le Goater return ibt->regs[TO_REG(offset)];
502*68857fbeSCédric Le Goater default:
503*68857fbeSCédric Le Goater qemu_log_mask(LOG_UNIMP, "%s: not implemented 0x%" HWADDR_PRIx "\n",
504*68857fbeSCédric Le Goater __func__, offset);
505*68857fbeSCédric Le Goater return 0;
506*68857fbeSCédric Le Goater }
507*68857fbeSCédric Le Goater
508*68857fbeSCédric Le Goater trace_aspeed_ibt_read(offset, val);
509*68857fbeSCédric Le Goater return val;
510*68857fbeSCédric Le Goater }
511*68857fbeSCédric Le Goater
512*68857fbeSCédric Le Goater static const MemoryRegionOps aspeed_ibt_ops = {
513*68857fbeSCédric Le Goater .read = aspeed_ibt_read,
514*68857fbeSCédric Le Goater .write = aspeed_ibt_write,
515*68857fbeSCédric Le Goater .endianness = DEVICE_LITTLE_ENDIAN,
516*68857fbeSCédric Le Goater .valid = {
517*68857fbeSCédric Le Goater .min_access_size = 1,
518*68857fbeSCédric Le Goater .max_access_size = 4,
519*68857fbeSCédric Le Goater },
520*68857fbeSCédric Le Goater };
521*68857fbeSCédric Le Goater
aspeed_ibt_reset(DeviceState * dev)522*68857fbeSCédric Le Goater static void aspeed_ibt_reset(DeviceState *dev)
523*68857fbeSCédric Le Goater {
524*68857fbeSCédric Le Goater AspeedIBTState *ibt = ASPEED_IBT(dev);
525*68857fbeSCédric Le Goater
526*68857fbeSCédric Le Goater memset(ibt->regs, 0, sizeof(ibt->regs));
527*68857fbeSCédric Le Goater
528*68857fbeSCédric Le Goater memset(ibt->recv_msg, 0, sizeof(ibt->recv_msg));
529*68857fbeSCédric Le Goater ibt->recv_msg_len = 0;
530*68857fbeSCédric Le Goater ibt->recv_msg_index = -1;
531*68857fbeSCédric Le Goater ibt->recv_msg_too_many = 0;
532*68857fbeSCédric Le Goater ibt->recv_waiting = false;
533*68857fbeSCédric Le Goater ibt->in_escape = 0;
534*68857fbeSCédric Le Goater
535*68857fbeSCédric Le Goater memset(ibt->send_msg, 0, sizeof(ibt->send_msg));
536*68857fbeSCédric Le Goater ibt->send_msg_len = 0;
537*68857fbeSCédric Le Goater }
538*68857fbeSCédric Le Goater
aspeed_ibt_realize(DeviceState * dev,Error ** errp)539*68857fbeSCédric Le Goater static void aspeed_ibt_realize(DeviceState *dev, Error **errp)
540*68857fbeSCédric Le Goater {
541*68857fbeSCédric Le Goater SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
542*68857fbeSCédric Le Goater AspeedIBTState *ibt = ASPEED_IBT(dev);
543*68857fbeSCédric Le Goater
544*68857fbeSCédric Le Goater if (!qemu_chr_fe_get_driver(&ibt->chr) && !qtest_enabled()) {
545*68857fbeSCédric Le Goater warn_report("Aspeed iBT has no chardev backend");
546*68857fbeSCédric Le Goater } else {
547*68857fbeSCédric Le Goater qemu_chr_fe_set_handlers(&ibt->chr, aspeed_ibt_chr_can_receive,
548*68857fbeSCédric Le Goater aspeed_ibt_chr_receive, aspeed_ibt_chr_event,
549*68857fbeSCédric Le Goater NULL, ibt, NULL, true);
550*68857fbeSCédric Le Goater }
551*68857fbeSCédric Le Goater
552*68857fbeSCédric Le Goater sysbus_init_irq(sbd, &ibt->irq);
553*68857fbeSCédric Le Goater memory_region_init_io(&ibt->iomem, OBJECT(ibt), &aspeed_ibt_ops, ibt,
554*68857fbeSCédric Le Goater TYPE_ASPEED_IBT, BT_IO_REGION_SIZE);
555*68857fbeSCédric Le Goater
556*68857fbeSCédric Le Goater sysbus_init_mmio(sbd, &ibt->iomem);
557*68857fbeSCédric Le Goater }
558*68857fbeSCédric Le Goater
559*68857fbeSCédric Le Goater static Property aspeed_ibt_props[] = {
560*68857fbeSCédric Le Goater DEFINE_PROP_CHR("chardev", AspeedIBTState, chr),
561*68857fbeSCédric Le Goater DEFINE_PROP_END_OF_LIST(),
562*68857fbeSCédric Le Goater };
563*68857fbeSCédric Le Goater
564*68857fbeSCédric Le Goater static const VMStateDescription vmstate_aspeed_ibt = {
565*68857fbeSCédric Le Goater .name = "aspeed.bt",
566*68857fbeSCédric Le Goater .version_id = 1,
567*68857fbeSCédric Le Goater .minimum_version_id = 1,
568*68857fbeSCédric Le Goater .fields = (VMStateField[]) {
569*68857fbeSCédric Le Goater VMSTATE_UINT32_ARRAY(regs, AspeedIBTState, ASPEED_IBT_NR_REGS),
570*68857fbeSCédric Le Goater VMSTATE_END_OF_LIST()
571*68857fbeSCédric Le Goater }
572*68857fbeSCédric Le Goater };
573*68857fbeSCédric Le Goater
aspeed_ibt_class_init(ObjectClass * klass,void * data)574*68857fbeSCédric Le Goater static void aspeed_ibt_class_init(ObjectClass *klass, void *data)
575*68857fbeSCédric Le Goater {
576*68857fbeSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass);
577*68857fbeSCédric Le Goater dc->realize = aspeed_ibt_realize;
578*68857fbeSCédric Le Goater device_class_set_legacy_reset(dc, aspeed_ibt_reset);
579*68857fbeSCédric Le Goater dc->desc = "ASPEED iBT Device";
580*68857fbeSCédric Le Goater dc->vmsd = &vmstate_aspeed_ibt;
581*68857fbeSCédric Le Goater device_class_set_props(dc, aspeed_ibt_props);
582*68857fbeSCédric Le Goater }
583*68857fbeSCédric Le Goater
584*68857fbeSCédric Le Goater static const TypeInfo aspeed_ibt_info = {
585*68857fbeSCédric Le Goater .name = TYPE_ASPEED_IBT,
586*68857fbeSCédric Le Goater .parent = TYPE_SYS_BUS_DEVICE,
587*68857fbeSCédric Le Goater .instance_size = sizeof(AspeedIBTState),
588*68857fbeSCédric Le Goater .class_init = aspeed_ibt_class_init,
589*68857fbeSCédric Le Goater };
590*68857fbeSCédric Le Goater
aspeed_ibt_register_types(void)591*68857fbeSCédric Le Goater static void aspeed_ibt_register_types(void)
592*68857fbeSCédric Le Goater {
593*68857fbeSCédric Le Goater type_register_static(&aspeed_ibt_info);
594*68857fbeSCédric Le Goater }
595*68857fbeSCédric Le Goater
596*68857fbeSCédric Le Goater type_init(aspeed_ibt_register_types);
597