xref: /qemu/hw/ipmi/isa_ipmi_bt.c (revision a9b74079cbf68720bbe9b409775bed8e1002cf4f)
1*a9b74079SCorey Minyard /*
2*a9b74079SCorey Minyard  * QEMU ISA IPMI BT emulation
3*a9b74079SCorey Minyard  *
4*a9b74079SCorey Minyard  * Copyright (c) 2015 Corey Minyard, MontaVista Software, LLC
5*a9b74079SCorey Minyard  *
6*a9b74079SCorey Minyard  * Permission is hereby granted, free of charge, to any person obtaining a copy
7*a9b74079SCorey Minyard  * of this software and associated documentation files (the "Software"), to deal
8*a9b74079SCorey Minyard  * in the Software without restriction, including without limitation the rights
9*a9b74079SCorey Minyard  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10*a9b74079SCorey Minyard  * copies of the Software, and to permit persons to whom the Software is
11*a9b74079SCorey Minyard  * furnished to do so, subject to the following conditions:
12*a9b74079SCorey Minyard  *
13*a9b74079SCorey Minyard  * The above copyright notice and this permission notice shall be included in
14*a9b74079SCorey Minyard  * all copies or substantial portions of the Software.
15*a9b74079SCorey Minyard  *
16*a9b74079SCorey Minyard  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17*a9b74079SCorey Minyard  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18*a9b74079SCorey Minyard  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19*a9b74079SCorey Minyard  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20*a9b74079SCorey Minyard  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21*a9b74079SCorey Minyard  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22*a9b74079SCorey Minyard  * THE SOFTWARE.
23*a9b74079SCorey Minyard  */
24*a9b74079SCorey Minyard #include "hw/hw.h"
25*a9b74079SCorey Minyard #include "hw/ipmi/ipmi.h"
26*a9b74079SCorey Minyard #include "hw/isa/isa.h"
27*a9b74079SCorey Minyard #include "hw/i386/pc.h"
28*a9b74079SCorey Minyard 
29*a9b74079SCorey Minyard /* Control register */
30*a9b74079SCorey Minyard #define IPMI_BT_CLR_WR_BIT         0
31*a9b74079SCorey Minyard #define IPMI_BT_CLR_RD_BIT         1
32*a9b74079SCorey Minyard #define IPMI_BT_H2B_ATN_BIT        2
33*a9b74079SCorey Minyard #define IPMI_BT_B2H_ATN_BIT        3
34*a9b74079SCorey Minyard #define IPMI_BT_SMS_ATN_BIT        4
35*a9b74079SCorey Minyard #define IPMI_BT_HBUSY_BIT          6
36*a9b74079SCorey Minyard #define IPMI_BT_BBUSY_BIT          7
37*a9b74079SCorey Minyard 
38*a9b74079SCorey Minyard #define IPMI_BT_CLR_WR_MASK        (1 << IPMI_BT_CLR_WR_BIT)
39*a9b74079SCorey Minyard #define IPMI_BT_GET_CLR_WR(d)      (((d) >> IPMI_BT_CLR_WR_BIT) & 0x1)
40*a9b74079SCorey Minyard #define IPMI_BT_SET_CLR_WR(d, v)   (d) = (((d) & ~IPMI_BT_CLR_WR_MASK) | \
41*a9b74079SCorey Minyard                                        (((v & 1) << IPMI_BT_CLR_WR_BIT)))
42*a9b74079SCorey Minyard 
43*a9b74079SCorey Minyard #define IPMI_BT_CLR_RD_MASK        (1 << IPMI_BT_CLR_RD_BIT)
44*a9b74079SCorey Minyard #define IPMI_BT_GET_CLR_RD(d)      (((d) >> IPMI_BT_CLR_RD_BIT) & 0x1)
45*a9b74079SCorey Minyard #define IPMI_BT_SET_CLR_RD(d, v)   (d) = (((d) & ~IPMI_BT_CLR_RD_MASK) | \
46*a9b74079SCorey Minyard                                        (((v & 1) << IPMI_BT_CLR_RD_BIT)))
47*a9b74079SCorey Minyard 
48*a9b74079SCorey Minyard #define IPMI_BT_H2B_ATN_MASK       (1 << IPMI_BT_H2B_ATN_BIT)
49*a9b74079SCorey Minyard #define IPMI_BT_GET_H2B_ATN(d)     (((d) >> IPMI_BT_H2B_ATN_BIT) & 0x1)
50*a9b74079SCorey Minyard #define IPMI_BT_SET_H2B_ATN(d, v)  (d) = (((d) & ~IPMI_BT_H2B_ATN_MASK) | \
51*a9b74079SCorey Minyard                                         (((v & 1) << IPMI_BT_H2B_ATN_BIT)))
52*a9b74079SCorey Minyard 
53*a9b74079SCorey Minyard #define IPMI_BT_B2H_ATN_MASK       (1 << IPMI_BT_B2H_ATN_BIT)
54*a9b74079SCorey Minyard #define IPMI_BT_GET_B2H_ATN(d)     (((d) >> IPMI_BT_B2H_ATN_BIT) & 0x1)
55*a9b74079SCorey Minyard #define IPMI_BT_SET_B2H_ATN(d, v)  (d) = (((d) & ~IPMI_BT_B2H_ATN_MASK) | \
56*a9b74079SCorey Minyard                                         (((v & 1) << IPMI_BT_B2H_ATN_BIT)))
57*a9b74079SCorey Minyard 
58*a9b74079SCorey Minyard #define IPMI_BT_SMS_ATN_MASK       (1 << IPMI_BT_SMS_ATN_BIT)
59*a9b74079SCorey Minyard #define IPMI_BT_GET_SMS_ATN(d)     (((d) >> IPMI_BT_SMS_ATN_BIT) & 0x1)
60*a9b74079SCorey Minyard #define IPMI_BT_SET_SMS_ATN(d, v)  (d) = (((d) & ~IPMI_BT_SMS_ATN_MASK) | \
61*a9b74079SCorey Minyard                                         (((v & 1) << IPMI_BT_SMS_ATN_BIT)))
62*a9b74079SCorey Minyard 
63*a9b74079SCorey Minyard #define IPMI_BT_HBUSY_MASK         (1 << IPMI_BT_HBUSY_BIT)
64*a9b74079SCorey Minyard #define IPMI_BT_GET_HBUSY(d)       (((d) >> IPMI_BT_HBUSY_BIT) & 0x1)
65*a9b74079SCorey Minyard #define IPMI_BT_SET_HBUSY(d, v)    (d) = (((d) & ~IPMI_BT_HBUSY_MASK) | \
66*a9b74079SCorey Minyard                                        (((v & 1) << IPMI_BT_HBUSY_BIT)))
67*a9b74079SCorey Minyard 
68*a9b74079SCorey Minyard #define IPMI_BT_BBUSY_MASK         (1 << IPMI_BT_BBUSY_BIT)
69*a9b74079SCorey Minyard #define IPMI_BT_GET_BBUSY(d)       (((d) >> IPMI_BT_BBUSY_BIT) & 0x1)
70*a9b74079SCorey Minyard #define IPMI_BT_SET_BBUSY(d, v)    (d) = (((d) & ~IPMI_BT_BBUSY_MASK) | \
71*a9b74079SCorey Minyard                                        (((v & 1) << IPMI_BT_BBUSY_BIT)))
72*a9b74079SCorey Minyard 
73*a9b74079SCorey Minyard 
74*a9b74079SCorey Minyard /* Mask register */
75*a9b74079SCorey Minyard #define IPMI_BT_B2H_IRQ_EN_BIT     0
76*a9b74079SCorey Minyard #define IPMI_BT_B2H_IRQ_BIT        1
77*a9b74079SCorey Minyard 
78*a9b74079SCorey Minyard #define IPMI_BT_B2H_IRQ_EN_MASK      (1 << IPMI_BT_B2H_IRQ_EN_BIT)
79*a9b74079SCorey Minyard #define IPMI_BT_GET_B2H_IRQ_EN(d)    (((d) >> IPMI_BT_B2H_IRQ_EN_BIT) & 0x1)
80*a9b74079SCorey Minyard #define IPMI_BT_SET_B2H_IRQ_EN(d, v) (d) = (((d) & ~IPMI_BT_B2H_IRQ_EN_MASK) | \
81*a9b74079SCorey Minyard                                         (((v & 1) << IPMI_BT_B2H_IRQ_EN_BIT)))
82*a9b74079SCorey Minyard 
83*a9b74079SCorey Minyard #define IPMI_BT_B2H_IRQ_MASK         (1 << IPMI_BT_B2H_IRQ_BIT)
84*a9b74079SCorey Minyard #define IPMI_BT_GET_B2H_IRQ(d)       (((d) >> IPMI_BT_B2H_IRQ_BIT) & 0x1)
85*a9b74079SCorey Minyard #define IPMI_BT_SET_B2H_IRQ(d, v)    (d) = (((d) & ~IPMI_BT_B2H_IRQ_MASK) | \
86*a9b74079SCorey Minyard                                         (((v & 1) << IPMI_BT_B2H_IRQ_BIT)))
87*a9b74079SCorey Minyard 
88*a9b74079SCorey Minyard typedef struct IPMIBT {
89*a9b74079SCorey Minyard     IPMIBmc *bmc;
90*a9b74079SCorey Minyard 
91*a9b74079SCorey Minyard     bool do_wake;
92*a9b74079SCorey Minyard 
93*a9b74079SCorey Minyard     qemu_irq irq;
94*a9b74079SCorey Minyard 
95*a9b74079SCorey Minyard     uint32_t io_base;
96*a9b74079SCorey Minyard     unsigned long io_length;
97*a9b74079SCorey Minyard     MemoryRegion io;
98*a9b74079SCorey Minyard 
99*a9b74079SCorey Minyard     bool obf_irq_set;
100*a9b74079SCorey Minyard     bool atn_irq_set;
101*a9b74079SCorey Minyard     bool use_irq;
102*a9b74079SCorey Minyard     bool irqs_enabled;
103*a9b74079SCorey Minyard 
104*a9b74079SCorey Minyard     uint8_t outmsg[MAX_IPMI_MSG_SIZE];
105*a9b74079SCorey Minyard     uint32_t outpos;
106*a9b74079SCorey Minyard     uint32_t outlen;
107*a9b74079SCorey Minyard 
108*a9b74079SCorey Minyard     uint8_t inmsg[MAX_IPMI_MSG_SIZE];
109*a9b74079SCorey Minyard     uint32_t inlen;
110*a9b74079SCorey Minyard 
111*a9b74079SCorey Minyard     uint8_t control_reg;
112*a9b74079SCorey Minyard     uint8_t mask_reg;
113*a9b74079SCorey Minyard 
114*a9b74079SCorey Minyard     /*
115*a9b74079SCorey Minyard      * This is a response number that we send with the command to make
116*a9b74079SCorey Minyard      * sure that the response matches the command.
117*a9b74079SCorey Minyard      */
118*a9b74079SCorey Minyard     uint8_t waiting_rsp;
119*a9b74079SCorey Minyard     uint8_t waiting_seq;
120*a9b74079SCorey Minyard } IPMIBT;
121*a9b74079SCorey Minyard 
122*a9b74079SCorey Minyard #define IPMI_CMD_GET_BT_INTF_CAP        0x36
123*a9b74079SCorey Minyard 
124*a9b74079SCorey Minyard static void ipmi_bt_handle_event(IPMIInterface *ii)
125*a9b74079SCorey Minyard {
126*a9b74079SCorey Minyard     IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
127*a9b74079SCorey Minyard     IPMIBT *ib = iic->get_backend_data(ii);
128*a9b74079SCorey Minyard 
129*a9b74079SCorey Minyard     if (ib->inlen < 4) {
130*a9b74079SCorey Minyard         goto out;
131*a9b74079SCorey Minyard     }
132*a9b74079SCorey Minyard     /* Note that overruns are handled by handle_command */
133*a9b74079SCorey Minyard     if (ib->inmsg[0] != (ib->inlen - 1)) {
134*a9b74079SCorey Minyard         /* Length mismatch, just ignore. */
135*a9b74079SCorey Minyard         IPMI_BT_SET_BBUSY(ib->control_reg, 1);
136*a9b74079SCorey Minyard         ib->inlen = 0;
137*a9b74079SCorey Minyard         goto out;
138*a9b74079SCorey Minyard     }
139*a9b74079SCorey Minyard     if ((ib->inmsg[1] == (IPMI_NETFN_APP << 2)) &&
140*a9b74079SCorey Minyard                         (ib->inmsg[3] == IPMI_CMD_GET_BT_INTF_CAP)) {
141*a9b74079SCorey Minyard         /* We handle this one ourselves. */
142*a9b74079SCorey Minyard         ib->outmsg[0] = 9;
143*a9b74079SCorey Minyard         ib->outmsg[1] = ib->inmsg[1] | 0x04;
144*a9b74079SCorey Minyard         ib->outmsg[2] = ib->inmsg[2];
145*a9b74079SCorey Minyard         ib->outmsg[3] = ib->inmsg[3];
146*a9b74079SCorey Minyard         ib->outmsg[4] = 0;
147*a9b74079SCorey Minyard         ib->outmsg[5] = 1; /* Only support 1 outstanding request. */
148*a9b74079SCorey Minyard         if (sizeof(ib->inmsg) > 0xff) { /* Input buffer size */
149*a9b74079SCorey Minyard             ib->outmsg[6] = 0xff;
150*a9b74079SCorey Minyard         } else {
151*a9b74079SCorey Minyard             ib->outmsg[6] = (unsigned char) sizeof(ib->inmsg);
152*a9b74079SCorey Minyard         }
153*a9b74079SCorey Minyard         if (sizeof(ib->outmsg) > 0xff) { /* Output buffer size */
154*a9b74079SCorey Minyard             ib->outmsg[7] = 0xff;
155*a9b74079SCorey Minyard         } else {
156*a9b74079SCorey Minyard             ib->outmsg[7] = (unsigned char) sizeof(ib->outmsg);
157*a9b74079SCorey Minyard         }
158*a9b74079SCorey Minyard         ib->outmsg[8] = 10; /* Max request to response time */
159*a9b74079SCorey Minyard         ib->outmsg[9] = 0; /* Don't recommend retries */
160*a9b74079SCorey Minyard         ib->outlen = 10;
161*a9b74079SCorey Minyard         IPMI_BT_SET_BBUSY(ib->control_reg, 0);
162*a9b74079SCorey Minyard         IPMI_BT_SET_B2H_ATN(ib->control_reg, 1);
163*a9b74079SCorey Minyard         if (ib->use_irq && ib->irqs_enabled &&
164*a9b74079SCorey Minyard                 !IPMI_BT_GET_B2H_IRQ(ib->mask_reg) &&
165*a9b74079SCorey Minyard                 IPMI_BT_GET_B2H_IRQ_EN(ib->mask_reg)) {
166*a9b74079SCorey Minyard             IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 1);
167*a9b74079SCorey Minyard             qemu_irq_raise(ib->irq);
168*a9b74079SCorey Minyard         }
169*a9b74079SCorey Minyard         goto out;
170*a9b74079SCorey Minyard     }
171*a9b74079SCorey Minyard     ib->waiting_seq = ib->inmsg[2];
172*a9b74079SCorey Minyard     ib->inmsg[2] = ib->inmsg[1];
173*a9b74079SCorey Minyard     {
174*a9b74079SCorey Minyard         IPMIBmcClass *bk = IPMI_BMC_GET_CLASS(ib->bmc);
175*a9b74079SCorey Minyard         bk->handle_command(ib->bmc, ib->inmsg + 2, ib->inlen - 2,
176*a9b74079SCorey Minyard                            sizeof(ib->inmsg), ib->waiting_rsp);
177*a9b74079SCorey Minyard     }
178*a9b74079SCorey Minyard  out:
179*a9b74079SCorey Minyard     return;
180*a9b74079SCorey Minyard }
181*a9b74079SCorey Minyard 
182*a9b74079SCorey Minyard static void ipmi_bt_handle_rsp(IPMIInterface *ii, uint8_t msg_id,
183*a9b74079SCorey Minyard                                 unsigned char *rsp, unsigned int rsp_len)
184*a9b74079SCorey Minyard {
185*a9b74079SCorey Minyard     IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
186*a9b74079SCorey Minyard     IPMIBT *ib = iic->get_backend_data(ii);
187*a9b74079SCorey Minyard 
188*a9b74079SCorey Minyard     if (ib->waiting_rsp == msg_id) {
189*a9b74079SCorey Minyard         ib->waiting_rsp++;
190*a9b74079SCorey Minyard         if (rsp_len > (sizeof(ib->outmsg) - 2)) {
191*a9b74079SCorey Minyard             ib->outmsg[0] = 4;
192*a9b74079SCorey Minyard             ib->outmsg[1] = rsp[0];
193*a9b74079SCorey Minyard             ib->outmsg[2] = ib->waiting_seq;
194*a9b74079SCorey Minyard             ib->outmsg[3] = rsp[1];
195*a9b74079SCorey Minyard             ib->outmsg[4] = IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES;
196*a9b74079SCorey Minyard             ib->outlen = 5;
197*a9b74079SCorey Minyard         } else {
198*a9b74079SCorey Minyard             ib->outmsg[0] = rsp_len + 1;
199*a9b74079SCorey Minyard             ib->outmsg[1] = rsp[0];
200*a9b74079SCorey Minyard             ib->outmsg[2] = ib->waiting_seq;
201*a9b74079SCorey Minyard             memcpy(ib->outmsg + 3, rsp + 1, rsp_len - 1);
202*a9b74079SCorey Minyard             ib->outlen = rsp_len + 2;
203*a9b74079SCorey Minyard         }
204*a9b74079SCorey Minyard         IPMI_BT_SET_BBUSY(ib->control_reg, 0);
205*a9b74079SCorey Minyard         IPMI_BT_SET_B2H_ATN(ib->control_reg, 1);
206*a9b74079SCorey Minyard         if (ib->use_irq && ib->irqs_enabled &&
207*a9b74079SCorey Minyard                 !IPMI_BT_GET_B2H_IRQ(ib->mask_reg) &&
208*a9b74079SCorey Minyard                 IPMI_BT_GET_B2H_IRQ_EN(ib->mask_reg)) {
209*a9b74079SCorey Minyard             IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 1);
210*a9b74079SCorey Minyard             qemu_irq_raise(ib->irq);
211*a9b74079SCorey Minyard         }
212*a9b74079SCorey Minyard     }
213*a9b74079SCorey Minyard }
214*a9b74079SCorey Minyard 
215*a9b74079SCorey Minyard 
216*a9b74079SCorey Minyard static uint64_t ipmi_bt_ioport_read(void *opaque, hwaddr addr, unsigned size)
217*a9b74079SCorey Minyard {
218*a9b74079SCorey Minyard     IPMIInterface *ii = opaque;
219*a9b74079SCorey Minyard     IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
220*a9b74079SCorey Minyard     IPMIBT *ib = iic->get_backend_data(ii);
221*a9b74079SCorey Minyard     uint32_t ret = 0xff;
222*a9b74079SCorey Minyard 
223*a9b74079SCorey Minyard     switch (addr & 3) {
224*a9b74079SCorey Minyard     case 0:
225*a9b74079SCorey Minyard         ret = ib->control_reg;
226*a9b74079SCorey Minyard         break;
227*a9b74079SCorey Minyard     case 1:
228*a9b74079SCorey Minyard         if (ib->outpos < ib->outlen) {
229*a9b74079SCorey Minyard             ret = ib->outmsg[ib->outpos];
230*a9b74079SCorey Minyard             ib->outpos++;
231*a9b74079SCorey Minyard             if (ib->outpos == ib->outlen) {
232*a9b74079SCorey Minyard                 ib->outpos = 0;
233*a9b74079SCorey Minyard                 ib->outlen = 0;
234*a9b74079SCorey Minyard             }
235*a9b74079SCorey Minyard         } else {
236*a9b74079SCorey Minyard             ret = 0xff;
237*a9b74079SCorey Minyard         }
238*a9b74079SCorey Minyard         break;
239*a9b74079SCorey Minyard     case 2:
240*a9b74079SCorey Minyard         ret = ib->mask_reg;
241*a9b74079SCorey Minyard         break;
242*a9b74079SCorey Minyard     }
243*a9b74079SCorey Minyard     return ret;
244*a9b74079SCorey Minyard }
245*a9b74079SCorey Minyard 
246*a9b74079SCorey Minyard static void ipmi_bt_signal(IPMIBT *ib, IPMIInterface *ii)
247*a9b74079SCorey Minyard {
248*a9b74079SCorey Minyard     IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
249*a9b74079SCorey Minyard 
250*a9b74079SCorey Minyard     ib->do_wake = 1;
251*a9b74079SCorey Minyard     while (ib->do_wake) {
252*a9b74079SCorey Minyard         ib->do_wake = 0;
253*a9b74079SCorey Minyard         iic->handle_if_event(ii);
254*a9b74079SCorey Minyard     }
255*a9b74079SCorey Minyard }
256*a9b74079SCorey Minyard 
257*a9b74079SCorey Minyard static void ipmi_bt_ioport_write(void *opaque, hwaddr addr, uint64_t val,
258*a9b74079SCorey Minyard                                  unsigned size)
259*a9b74079SCorey Minyard {
260*a9b74079SCorey Minyard     IPMIInterface *ii = opaque;
261*a9b74079SCorey Minyard     IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
262*a9b74079SCorey Minyard     IPMIBT *ib = iic->get_backend_data(ii);
263*a9b74079SCorey Minyard 
264*a9b74079SCorey Minyard     switch (addr & 3) {
265*a9b74079SCorey Minyard     case 0:
266*a9b74079SCorey Minyard         if (IPMI_BT_GET_CLR_WR(val)) {
267*a9b74079SCorey Minyard             ib->inlen = 0;
268*a9b74079SCorey Minyard         }
269*a9b74079SCorey Minyard         if (IPMI_BT_GET_CLR_RD(val)) {
270*a9b74079SCorey Minyard             ib->outpos = 0;
271*a9b74079SCorey Minyard         }
272*a9b74079SCorey Minyard         if (IPMI_BT_GET_B2H_ATN(val)) {
273*a9b74079SCorey Minyard             IPMI_BT_SET_B2H_ATN(ib->control_reg, 0);
274*a9b74079SCorey Minyard         }
275*a9b74079SCorey Minyard         if (IPMI_BT_GET_SMS_ATN(val)) {
276*a9b74079SCorey Minyard             IPMI_BT_SET_SMS_ATN(ib->control_reg, 0);
277*a9b74079SCorey Minyard         }
278*a9b74079SCorey Minyard         if (IPMI_BT_GET_HBUSY(val)) {
279*a9b74079SCorey Minyard             /* Toggle */
280*a9b74079SCorey Minyard             IPMI_BT_SET_HBUSY(ib->control_reg,
281*a9b74079SCorey Minyard                               !IPMI_BT_GET_HBUSY(ib->control_reg));
282*a9b74079SCorey Minyard         }
283*a9b74079SCorey Minyard         if (IPMI_BT_GET_H2B_ATN(val)) {
284*a9b74079SCorey Minyard             IPMI_BT_SET_BBUSY(ib->control_reg, 1);
285*a9b74079SCorey Minyard             ipmi_bt_signal(ib, ii);
286*a9b74079SCorey Minyard         }
287*a9b74079SCorey Minyard         break;
288*a9b74079SCorey Minyard 
289*a9b74079SCorey Minyard     case 1:
290*a9b74079SCorey Minyard         if (ib->inlen < sizeof(ib->inmsg)) {
291*a9b74079SCorey Minyard             ib->inmsg[ib->inlen] = val;
292*a9b74079SCorey Minyard         }
293*a9b74079SCorey Minyard         ib->inlen++;
294*a9b74079SCorey Minyard         break;
295*a9b74079SCorey Minyard 
296*a9b74079SCorey Minyard     case 2:
297*a9b74079SCorey Minyard         if (IPMI_BT_GET_B2H_IRQ_EN(val) !=
298*a9b74079SCorey Minyard                         IPMI_BT_GET_B2H_IRQ_EN(ib->mask_reg)) {
299*a9b74079SCorey Minyard             if (IPMI_BT_GET_B2H_IRQ_EN(val)) {
300*a9b74079SCorey Minyard                 if (IPMI_BT_GET_B2H_ATN(ib->control_reg) ||
301*a9b74079SCorey Minyard                         IPMI_BT_GET_SMS_ATN(ib->control_reg)) {
302*a9b74079SCorey Minyard                     IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 1);
303*a9b74079SCorey Minyard                     qemu_irq_raise(ib->irq);
304*a9b74079SCorey Minyard                 }
305*a9b74079SCorey Minyard                 IPMI_BT_SET_B2H_IRQ_EN(ib->mask_reg, 1);
306*a9b74079SCorey Minyard             } else {
307*a9b74079SCorey Minyard                 if (IPMI_BT_GET_B2H_IRQ(ib->mask_reg)) {
308*a9b74079SCorey Minyard                     IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 0);
309*a9b74079SCorey Minyard                     qemu_irq_lower(ib->irq);
310*a9b74079SCorey Minyard                 }
311*a9b74079SCorey Minyard                 IPMI_BT_SET_B2H_IRQ_EN(ib->mask_reg, 0);
312*a9b74079SCorey Minyard             }
313*a9b74079SCorey Minyard         }
314*a9b74079SCorey Minyard         if (IPMI_BT_GET_B2H_IRQ(val) && IPMI_BT_GET_B2H_IRQ(ib->mask_reg)) {
315*a9b74079SCorey Minyard             IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 0);
316*a9b74079SCorey Minyard             qemu_irq_lower(ib->irq);
317*a9b74079SCorey Minyard         }
318*a9b74079SCorey Minyard         break;
319*a9b74079SCorey Minyard     }
320*a9b74079SCorey Minyard }
321*a9b74079SCorey Minyard 
322*a9b74079SCorey Minyard static const MemoryRegionOps ipmi_bt_io_ops = {
323*a9b74079SCorey Minyard     .read = ipmi_bt_ioport_read,
324*a9b74079SCorey Minyard     .write = ipmi_bt_ioport_write,
325*a9b74079SCorey Minyard     .impl = {
326*a9b74079SCorey Minyard         .min_access_size = 1,
327*a9b74079SCorey Minyard         .max_access_size = 1,
328*a9b74079SCorey Minyard     },
329*a9b74079SCorey Minyard     .endianness = DEVICE_LITTLE_ENDIAN,
330*a9b74079SCorey Minyard };
331*a9b74079SCorey Minyard 
332*a9b74079SCorey Minyard static void ipmi_bt_set_atn(IPMIInterface *ii, int val, int irq)
333*a9b74079SCorey Minyard {
334*a9b74079SCorey Minyard     IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
335*a9b74079SCorey Minyard     IPMIBT *ib = iic->get_backend_data(ii);
336*a9b74079SCorey Minyard 
337*a9b74079SCorey Minyard     if (!!val == IPMI_BT_GET_SMS_ATN(ib->control_reg)) {
338*a9b74079SCorey Minyard         return;
339*a9b74079SCorey Minyard     }
340*a9b74079SCorey Minyard 
341*a9b74079SCorey Minyard     IPMI_BT_SET_SMS_ATN(ib->control_reg, val);
342*a9b74079SCorey Minyard     if (val) {
343*a9b74079SCorey Minyard         if (irq && ib->use_irq && ib->irqs_enabled &&
344*a9b74079SCorey Minyard                 !IPMI_BT_GET_B2H_ATN(ib->control_reg) &&
345*a9b74079SCorey Minyard                 IPMI_BT_GET_B2H_IRQ_EN(ib->mask_reg)) {
346*a9b74079SCorey Minyard             IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 1);
347*a9b74079SCorey Minyard             qemu_irq_raise(ib->irq);
348*a9b74079SCorey Minyard         }
349*a9b74079SCorey Minyard     } else {
350*a9b74079SCorey Minyard         if (!IPMI_BT_GET_B2H_ATN(ib->control_reg) &&
351*a9b74079SCorey Minyard                 IPMI_BT_GET_B2H_IRQ(ib->mask_reg)) {
352*a9b74079SCorey Minyard             IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 0);
353*a9b74079SCorey Minyard             qemu_irq_lower(ib->irq);
354*a9b74079SCorey Minyard         }
355*a9b74079SCorey Minyard     }
356*a9b74079SCorey Minyard }
357*a9b74079SCorey Minyard 
358*a9b74079SCorey Minyard static void ipmi_bt_handle_reset(IPMIInterface *ii, bool is_cold)
359*a9b74079SCorey Minyard {
360*a9b74079SCorey Minyard     IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
361*a9b74079SCorey Minyard     IPMIBT *ib = iic->get_backend_data(ii);
362*a9b74079SCorey Minyard 
363*a9b74079SCorey Minyard     if (is_cold) {
364*a9b74079SCorey Minyard         /* Disable the BT interrupt on reset */
365*a9b74079SCorey Minyard         if (IPMI_BT_GET_B2H_IRQ(ib->mask_reg)) {
366*a9b74079SCorey Minyard             IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 0);
367*a9b74079SCorey Minyard             qemu_irq_lower(ib->irq);
368*a9b74079SCorey Minyard         }
369*a9b74079SCorey Minyard         IPMI_BT_SET_B2H_IRQ_EN(ib->mask_reg, 0);
370*a9b74079SCorey Minyard     }
371*a9b74079SCorey Minyard }
372*a9b74079SCorey Minyard 
373*a9b74079SCorey Minyard static void ipmi_bt_set_irq_enable(IPMIInterface *ii, int val)
374*a9b74079SCorey Minyard {
375*a9b74079SCorey Minyard     IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
376*a9b74079SCorey Minyard     IPMIBT *ib = iic->get_backend_data(ii);
377*a9b74079SCorey Minyard 
378*a9b74079SCorey Minyard     ib->irqs_enabled = val;
379*a9b74079SCorey Minyard }
380*a9b74079SCorey Minyard 
381*a9b74079SCorey Minyard static void ipmi_bt_init(IPMIInterface *ii, Error **errp)
382*a9b74079SCorey Minyard {
383*a9b74079SCorey Minyard     IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
384*a9b74079SCorey Minyard     IPMIBT *ib = iic->get_backend_data(ii);
385*a9b74079SCorey Minyard 
386*a9b74079SCorey Minyard     ib->io_length = 3;
387*a9b74079SCorey Minyard 
388*a9b74079SCorey Minyard     memory_region_init_io(&ib->io, NULL, &ipmi_bt_io_ops, ii, "ipmi-bt", 3);
389*a9b74079SCorey Minyard }
390*a9b74079SCorey Minyard 
391*a9b74079SCorey Minyard static void ipmi_bt_class_init(IPMIInterfaceClass *iic)
392*a9b74079SCorey Minyard {
393*a9b74079SCorey Minyard     iic->init = ipmi_bt_init;
394*a9b74079SCorey Minyard     iic->set_atn = ipmi_bt_set_atn;
395*a9b74079SCorey Minyard     iic->handle_rsp = ipmi_bt_handle_rsp;
396*a9b74079SCorey Minyard     iic->handle_if_event = ipmi_bt_handle_event;
397*a9b74079SCorey Minyard     iic->set_irq_enable = ipmi_bt_set_irq_enable;
398*a9b74079SCorey Minyard     iic->reset = ipmi_bt_handle_reset;
399*a9b74079SCorey Minyard }
400*a9b74079SCorey Minyard 
401*a9b74079SCorey Minyard 
402*a9b74079SCorey Minyard #define TYPE_ISA_IPMI_BT "isa-ipmi-bt"
403*a9b74079SCorey Minyard #define ISA_IPMI_BT(obj) OBJECT_CHECK(ISAIPMIBTDevice, (obj), \
404*a9b74079SCorey Minyard                                        TYPE_ISA_IPMI_BT)
405*a9b74079SCorey Minyard 
406*a9b74079SCorey Minyard typedef struct ISAIPMIBTDevice {
407*a9b74079SCorey Minyard     ISADevice dev;
408*a9b74079SCorey Minyard     int32 isairq;
409*a9b74079SCorey Minyard     IPMIBT bt;
410*a9b74079SCorey Minyard } ISAIPMIBTDevice;
411*a9b74079SCorey Minyard 
412*a9b74079SCorey Minyard static void isa_ipmi_bt_realize(DeviceState *dev, Error **errp)
413*a9b74079SCorey Minyard {
414*a9b74079SCorey Minyard     ISADevice *isadev = ISA_DEVICE(dev);
415*a9b74079SCorey Minyard     ISAIPMIBTDevice *iib = ISA_IPMI_BT(dev);
416*a9b74079SCorey Minyard     IPMIInterface *ii = IPMI_INTERFACE(dev);
417*a9b74079SCorey Minyard     IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
418*a9b74079SCorey Minyard 
419*a9b74079SCorey Minyard     if (!iib->bt.bmc) {
420*a9b74079SCorey Minyard         error_setg(errp, "IPMI device requires a bmc attribute to be set");
421*a9b74079SCorey Minyard         return;
422*a9b74079SCorey Minyard     }
423*a9b74079SCorey Minyard 
424*a9b74079SCorey Minyard     iib->bt.bmc->intf = ii;
425*a9b74079SCorey Minyard 
426*a9b74079SCorey Minyard     iic->init(ii, errp);
427*a9b74079SCorey Minyard     if (*errp)
428*a9b74079SCorey Minyard         return;
429*a9b74079SCorey Minyard 
430*a9b74079SCorey Minyard     if (iib->isairq > 0) {
431*a9b74079SCorey Minyard         isa_init_irq(isadev, &iib->bt.irq, iib->isairq);
432*a9b74079SCorey Minyard         iib->bt.use_irq = 1;
433*a9b74079SCorey Minyard     }
434*a9b74079SCorey Minyard 
435*a9b74079SCorey Minyard     qdev_set_legacy_instance_id(dev, iib->bt.io_base, iib->bt.io_length);
436*a9b74079SCorey Minyard 
437*a9b74079SCorey Minyard     isa_register_ioport(isadev, &iib->bt.io, iib->bt.io_base);
438*a9b74079SCorey Minyard }
439*a9b74079SCorey Minyard 
440*a9b74079SCorey Minyard static void isa_ipmi_bt_init(Object *obj)
441*a9b74079SCorey Minyard {
442*a9b74079SCorey Minyard     ISAIPMIBTDevice *iib = ISA_IPMI_BT(obj);
443*a9b74079SCorey Minyard 
444*a9b74079SCorey Minyard     ipmi_bmc_find_and_link(obj, (Object **) &iib->bt.bmc);
445*a9b74079SCorey Minyard }
446*a9b74079SCorey Minyard 
447*a9b74079SCorey Minyard static void *isa_ipmi_bt_get_backend_data(IPMIInterface *ii)
448*a9b74079SCorey Minyard {
449*a9b74079SCorey Minyard     ISAIPMIBTDevice *iib = ISA_IPMI_BT(ii);
450*a9b74079SCorey Minyard 
451*a9b74079SCorey Minyard     return &iib->bt;
452*a9b74079SCorey Minyard }
453*a9b74079SCorey Minyard 
454*a9b74079SCorey Minyard static Property ipmi_isa_properties[] = {
455*a9b74079SCorey Minyard     DEFINE_PROP_UINT32("ioport", ISAIPMIBTDevice, bt.io_base,  0xe4),
456*a9b74079SCorey Minyard     DEFINE_PROP_INT32("irq",   ISAIPMIBTDevice, isairq,  5),
457*a9b74079SCorey Minyard     DEFINE_PROP_END_OF_LIST(),
458*a9b74079SCorey Minyard };
459*a9b74079SCorey Minyard 
460*a9b74079SCorey Minyard static void isa_ipmi_bt_class_init(ObjectClass *oc, void *data)
461*a9b74079SCorey Minyard {
462*a9b74079SCorey Minyard     DeviceClass *dc = DEVICE_CLASS(oc);
463*a9b74079SCorey Minyard     IPMIInterfaceClass *iic = IPMI_INTERFACE_CLASS(oc);
464*a9b74079SCorey Minyard 
465*a9b74079SCorey Minyard     dc->realize = isa_ipmi_bt_realize;
466*a9b74079SCorey Minyard     dc->props = ipmi_isa_properties;
467*a9b74079SCorey Minyard 
468*a9b74079SCorey Minyard     iic->get_backend_data = isa_ipmi_bt_get_backend_data;
469*a9b74079SCorey Minyard     ipmi_bt_class_init(iic);
470*a9b74079SCorey Minyard }
471*a9b74079SCorey Minyard 
472*a9b74079SCorey Minyard static const TypeInfo isa_ipmi_bt_info = {
473*a9b74079SCorey Minyard     .name          = TYPE_ISA_IPMI_BT,
474*a9b74079SCorey Minyard     .parent        = TYPE_ISA_DEVICE,
475*a9b74079SCorey Minyard     .instance_size = sizeof(ISAIPMIBTDevice),
476*a9b74079SCorey Minyard     .instance_init = isa_ipmi_bt_init,
477*a9b74079SCorey Minyard     .class_init    = isa_ipmi_bt_class_init,
478*a9b74079SCorey Minyard     .interfaces = (InterfaceInfo[]) {
479*a9b74079SCorey Minyard         { TYPE_IPMI_INTERFACE },
480*a9b74079SCorey Minyard         { }
481*a9b74079SCorey Minyard     }
482*a9b74079SCorey Minyard };
483*a9b74079SCorey Minyard 
484*a9b74079SCorey Minyard static void ipmi_register_types(void)
485*a9b74079SCorey Minyard {
486*a9b74079SCorey Minyard     type_register_static(&isa_ipmi_bt_info);
487*a9b74079SCorey Minyard }
488*a9b74079SCorey Minyard 
489*a9b74079SCorey Minyard type_init(ipmi_register_types)
490