xref: /qemu/hw/ipmi/isa_ipmi_kcs.c (revision 0719029c47b28404cf307f184934c8281a424918)
1*0719029cSCorey Minyard /*
2*0719029cSCorey Minyard  * QEMU ISA IPMI KCS emulation
3*0719029cSCorey Minyard  *
4*0719029cSCorey Minyard  * Copyright (c) 2015 Corey Minyard, MontaVista Software, LLC
5*0719029cSCorey Minyard  *
6*0719029cSCorey Minyard  * Permission is hereby granted, free of charge, to any person obtaining a copy
7*0719029cSCorey Minyard  * of this software and associated documentation files (the "Software"), to deal
8*0719029cSCorey Minyard  * in the Software without restriction, including without limitation the rights
9*0719029cSCorey Minyard  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10*0719029cSCorey Minyard  * copies of the Software, and to permit persons to whom the Software is
11*0719029cSCorey Minyard  * furnished to do so, subject to the following conditions:
12*0719029cSCorey Minyard  *
13*0719029cSCorey Minyard  * The above copyright notice and this permission notice shall be included in
14*0719029cSCorey Minyard  * all copies or substantial portions of the Software.
15*0719029cSCorey Minyard  *
16*0719029cSCorey Minyard  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17*0719029cSCorey Minyard  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18*0719029cSCorey Minyard  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19*0719029cSCorey Minyard  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20*0719029cSCorey Minyard  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21*0719029cSCorey Minyard  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22*0719029cSCorey Minyard  * THE SOFTWARE.
23*0719029cSCorey Minyard  */
24*0719029cSCorey Minyard #include "hw/hw.h"
25*0719029cSCorey Minyard #include "hw/ipmi/ipmi.h"
26*0719029cSCorey Minyard #include "hw/isa/isa.h"
27*0719029cSCorey Minyard #include "hw/i386/pc.h"
28*0719029cSCorey Minyard 
29*0719029cSCorey Minyard #define IPMI_KCS_OBF_BIT        0
30*0719029cSCorey Minyard #define IPMI_KCS_IBF_BIT        1
31*0719029cSCorey Minyard #define IPMI_KCS_SMS_ATN_BIT    2
32*0719029cSCorey Minyard #define IPMI_KCS_CD_BIT         3
33*0719029cSCorey Minyard 
34*0719029cSCorey Minyard #define IPMI_KCS_OBF_MASK          (1 << IPMI_KCS_OBF_BIT)
35*0719029cSCorey Minyard #define IPMI_KCS_GET_OBF(d)        (((d) >> IPMI_KCS_OBF_BIT) & 0x1)
36*0719029cSCorey Minyard #define IPMI_KCS_SET_OBF(d, v)     (d) = (((d) & ~IPMI_KCS_OBF_MASK) | \
37*0719029cSCorey Minyard                                        (((v) & 1) << IPMI_KCS_OBF_BIT))
38*0719029cSCorey Minyard #define IPMI_KCS_IBF_MASK          (1 << IPMI_KCS_IBF_BIT)
39*0719029cSCorey Minyard #define IPMI_KCS_GET_IBF(d)        (((d) >> IPMI_KCS_IBF_BIT) & 0x1)
40*0719029cSCorey Minyard #define IPMI_KCS_SET_IBF(d, v)     (d) = (((d) & ~IPMI_KCS_IBF_MASK) | \
41*0719029cSCorey Minyard                                        (((v) & 1) << IPMI_KCS_IBF_BIT))
42*0719029cSCorey Minyard #define IPMI_KCS_SMS_ATN_MASK      (1 << IPMI_KCS_SMS_ATN_BIT)
43*0719029cSCorey Minyard #define IPMI_KCS_GET_SMS_ATN(d)    (((d) >> IPMI_KCS_SMS_ATN_BIT) & 0x1)
44*0719029cSCorey Minyard #define IPMI_KCS_SET_SMS_ATN(d, v) (d) = (((d) & ~IPMI_KCS_SMS_ATN_MASK) | \
45*0719029cSCorey Minyard                                        (((v) & 1) << IPMI_KCS_SMS_ATN_BIT))
46*0719029cSCorey Minyard #define IPMI_KCS_CD_MASK           (1 << IPMI_KCS_CD_BIT)
47*0719029cSCorey Minyard #define IPMI_KCS_GET_CD(d)         (((d) >> IPMI_KCS_CD_BIT) & 0x1)
48*0719029cSCorey Minyard #define IPMI_KCS_SET_CD(d, v)      (d) = (((d) & ~IPMI_KCS_CD_MASK) | \
49*0719029cSCorey Minyard                                        (((v) & 1) << IPMI_KCS_CD_BIT))
50*0719029cSCorey Minyard 
51*0719029cSCorey Minyard #define IPMI_KCS_IDLE_STATE        0
52*0719029cSCorey Minyard #define IPMI_KCS_READ_STATE        1
53*0719029cSCorey Minyard #define IPMI_KCS_WRITE_STATE       2
54*0719029cSCorey Minyard #define IPMI_KCS_ERROR_STATE       3
55*0719029cSCorey Minyard 
56*0719029cSCorey Minyard #define IPMI_KCS_GET_STATE(d)    (((d) >> 6) & 0x3)
57*0719029cSCorey Minyard #define IPMI_KCS_SET_STATE(d, v) ((d) = ((d) & ~0xc0) | (((v) & 0x3) << 6))
58*0719029cSCorey Minyard 
59*0719029cSCorey Minyard #define IPMI_KCS_ABORT_STATUS_CMD       0x60
60*0719029cSCorey Minyard #define IPMI_KCS_WRITE_START_CMD        0x61
61*0719029cSCorey Minyard #define IPMI_KCS_WRITE_END_CMD          0x62
62*0719029cSCorey Minyard #define IPMI_KCS_READ_CMD               0x68
63*0719029cSCorey Minyard 
64*0719029cSCorey Minyard #define IPMI_KCS_STATUS_NO_ERR          0x00
65*0719029cSCorey Minyard #define IPMI_KCS_STATUS_ABORTED_ERR     0x01
66*0719029cSCorey Minyard #define IPMI_KCS_STATUS_BAD_CC_ERR      0x02
67*0719029cSCorey Minyard #define IPMI_KCS_STATUS_LENGTH_ERR      0x06
68*0719029cSCorey Minyard 
69*0719029cSCorey Minyard typedef struct IPMIKCS {
70*0719029cSCorey Minyard     IPMIBmc *bmc;
71*0719029cSCorey Minyard 
72*0719029cSCorey Minyard     bool do_wake;
73*0719029cSCorey Minyard 
74*0719029cSCorey Minyard     qemu_irq irq;
75*0719029cSCorey Minyard 
76*0719029cSCorey Minyard     uint32_t io_base;
77*0719029cSCorey Minyard     unsigned long io_length;
78*0719029cSCorey Minyard     MemoryRegion io;
79*0719029cSCorey Minyard 
80*0719029cSCorey Minyard     bool obf_irq_set;
81*0719029cSCorey Minyard     bool atn_irq_set;
82*0719029cSCorey Minyard     bool use_irq;
83*0719029cSCorey Minyard     bool irqs_enabled;
84*0719029cSCorey Minyard 
85*0719029cSCorey Minyard     uint8_t outmsg[MAX_IPMI_MSG_SIZE];
86*0719029cSCorey Minyard     uint32_t outpos;
87*0719029cSCorey Minyard     uint32_t outlen;
88*0719029cSCorey Minyard 
89*0719029cSCorey Minyard     uint8_t inmsg[MAX_IPMI_MSG_SIZE];
90*0719029cSCorey Minyard     uint32_t inlen;
91*0719029cSCorey Minyard     bool write_end;
92*0719029cSCorey Minyard 
93*0719029cSCorey Minyard     uint8_t status_reg;
94*0719029cSCorey Minyard     uint8_t data_out_reg;
95*0719029cSCorey Minyard 
96*0719029cSCorey Minyard     int16_t data_in_reg; /* -1 means not written */
97*0719029cSCorey Minyard     int16_t cmd_reg;
98*0719029cSCorey Minyard 
99*0719029cSCorey Minyard     /*
100*0719029cSCorey Minyard      * This is a response number that we send with the command to make
101*0719029cSCorey Minyard      * sure that the response matches the command.
102*0719029cSCorey Minyard      */
103*0719029cSCorey Minyard     uint8_t waiting_rsp;
104*0719029cSCorey Minyard } IPMIKCS;
105*0719029cSCorey Minyard 
106*0719029cSCorey Minyard #define SET_OBF() \
107*0719029cSCorey Minyard     do {                                                                      \
108*0719029cSCorey Minyard         IPMI_KCS_SET_OBF(ik->status_reg, 1);                                  \
109*0719029cSCorey Minyard         if (ik->use_irq && ik->irqs_enabled && !ik->obf_irq_set) {            \
110*0719029cSCorey Minyard             ik->obf_irq_set = 1;                                              \
111*0719029cSCorey Minyard             if (!ik->atn_irq_set) {                                           \
112*0719029cSCorey Minyard                 qemu_irq_raise(ik->irq);                                      \
113*0719029cSCorey Minyard             }                                                                 \
114*0719029cSCorey Minyard         }                                                                     \
115*0719029cSCorey Minyard     } while (0)
116*0719029cSCorey Minyard 
117*0719029cSCorey Minyard static void ipmi_kcs_signal(IPMIKCS *ik, IPMIInterface *ii)
118*0719029cSCorey Minyard {
119*0719029cSCorey Minyard     IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
120*0719029cSCorey Minyard 
121*0719029cSCorey Minyard     ik->do_wake = 1;
122*0719029cSCorey Minyard     while (ik->do_wake) {
123*0719029cSCorey Minyard         ik->do_wake = 0;
124*0719029cSCorey Minyard         iic->handle_if_event(ii);
125*0719029cSCorey Minyard     }
126*0719029cSCorey Minyard }
127*0719029cSCorey Minyard 
128*0719029cSCorey Minyard static void ipmi_kcs_handle_event(IPMIInterface *ii)
129*0719029cSCorey Minyard {
130*0719029cSCorey Minyard     IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
131*0719029cSCorey Minyard     IPMIKCS *ik = iic->get_backend_data(ii);
132*0719029cSCorey Minyard 
133*0719029cSCorey Minyard     if (ik->cmd_reg == IPMI_KCS_ABORT_STATUS_CMD) {
134*0719029cSCorey Minyard         if (IPMI_KCS_GET_STATE(ik->status_reg) != IPMI_KCS_ERROR_STATE) {
135*0719029cSCorey Minyard             ik->waiting_rsp++; /* Invalidate the message */
136*0719029cSCorey Minyard             ik->outmsg[0] = IPMI_KCS_STATUS_ABORTED_ERR;
137*0719029cSCorey Minyard             ik->outlen = 1;
138*0719029cSCorey Minyard             ik->outpos = 0;
139*0719029cSCorey Minyard             IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_ERROR_STATE);
140*0719029cSCorey Minyard             SET_OBF();
141*0719029cSCorey Minyard         }
142*0719029cSCorey Minyard         goto out;
143*0719029cSCorey Minyard     }
144*0719029cSCorey Minyard 
145*0719029cSCorey Minyard     switch (IPMI_KCS_GET_STATE(ik->status_reg)) {
146*0719029cSCorey Minyard     case IPMI_KCS_IDLE_STATE:
147*0719029cSCorey Minyard         if (ik->cmd_reg == IPMI_KCS_WRITE_START_CMD) {
148*0719029cSCorey Minyard             IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_WRITE_STATE);
149*0719029cSCorey Minyard             ik->cmd_reg = -1;
150*0719029cSCorey Minyard             ik->write_end = 0;
151*0719029cSCorey Minyard             ik->inlen = 0;
152*0719029cSCorey Minyard             SET_OBF();
153*0719029cSCorey Minyard         }
154*0719029cSCorey Minyard         break;
155*0719029cSCorey Minyard 
156*0719029cSCorey Minyard     case IPMI_KCS_READ_STATE:
157*0719029cSCorey Minyard     handle_read:
158*0719029cSCorey Minyard         if (ik->outpos >= ik->outlen) {
159*0719029cSCorey Minyard             IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_IDLE_STATE);
160*0719029cSCorey Minyard             SET_OBF();
161*0719029cSCorey Minyard         } else if (ik->data_in_reg == IPMI_KCS_READ_CMD) {
162*0719029cSCorey Minyard             ik->data_out_reg = ik->outmsg[ik->outpos];
163*0719029cSCorey Minyard             ik->outpos++;
164*0719029cSCorey Minyard             SET_OBF();
165*0719029cSCorey Minyard         } else {
166*0719029cSCorey Minyard             ik->outmsg[0] = IPMI_KCS_STATUS_BAD_CC_ERR;
167*0719029cSCorey Minyard             ik->outlen = 1;
168*0719029cSCorey Minyard             ik->outpos = 0;
169*0719029cSCorey Minyard             IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_ERROR_STATE);
170*0719029cSCorey Minyard             SET_OBF();
171*0719029cSCorey Minyard             goto out;
172*0719029cSCorey Minyard         }
173*0719029cSCorey Minyard         break;
174*0719029cSCorey Minyard 
175*0719029cSCorey Minyard     case IPMI_KCS_WRITE_STATE:
176*0719029cSCorey Minyard         if (ik->data_in_reg != -1) {
177*0719029cSCorey Minyard             /*
178*0719029cSCorey Minyard              * Don't worry about input overrun here, that will be
179*0719029cSCorey Minyard              * handled in the BMC.
180*0719029cSCorey Minyard              */
181*0719029cSCorey Minyard             if (ik->inlen < sizeof(ik->inmsg)) {
182*0719029cSCorey Minyard                 ik->inmsg[ik->inlen] = ik->data_in_reg;
183*0719029cSCorey Minyard             }
184*0719029cSCorey Minyard             ik->inlen++;
185*0719029cSCorey Minyard         }
186*0719029cSCorey Minyard         if (ik->write_end) {
187*0719029cSCorey Minyard             IPMIBmcClass *bk = IPMI_BMC_GET_CLASS(ik->bmc);
188*0719029cSCorey Minyard             ik->outlen = 0;
189*0719029cSCorey Minyard             ik->write_end = 0;
190*0719029cSCorey Minyard             ik->outpos = 0;
191*0719029cSCorey Minyard             bk->handle_command(ik->bmc, ik->inmsg, ik->inlen, sizeof(ik->inmsg),
192*0719029cSCorey Minyard                                ik->waiting_rsp);
193*0719029cSCorey Minyard             goto out_noibf;
194*0719029cSCorey Minyard         } else if (ik->cmd_reg == IPMI_KCS_WRITE_END_CMD) {
195*0719029cSCorey Minyard             ik->cmd_reg = -1;
196*0719029cSCorey Minyard             ik->write_end = 1;
197*0719029cSCorey Minyard         }
198*0719029cSCorey Minyard         SET_OBF();
199*0719029cSCorey Minyard         break;
200*0719029cSCorey Minyard 
201*0719029cSCorey Minyard     case IPMI_KCS_ERROR_STATE:
202*0719029cSCorey Minyard         if (ik->data_in_reg != -1) {
203*0719029cSCorey Minyard             IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_READ_STATE);
204*0719029cSCorey Minyard             ik->data_in_reg = IPMI_KCS_READ_CMD;
205*0719029cSCorey Minyard             goto handle_read;
206*0719029cSCorey Minyard         }
207*0719029cSCorey Minyard         break;
208*0719029cSCorey Minyard     }
209*0719029cSCorey Minyard 
210*0719029cSCorey Minyard     if (ik->cmd_reg != -1) {
211*0719029cSCorey Minyard         /* Got an invalid command */
212*0719029cSCorey Minyard         ik->outmsg[0] = IPMI_KCS_STATUS_BAD_CC_ERR;
213*0719029cSCorey Minyard         ik->outlen = 1;
214*0719029cSCorey Minyard         ik->outpos = 0;
215*0719029cSCorey Minyard         IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_ERROR_STATE);
216*0719029cSCorey Minyard     }
217*0719029cSCorey Minyard 
218*0719029cSCorey Minyard  out:
219*0719029cSCorey Minyard     ik->cmd_reg = -1;
220*0719029cSCorey Minyard     ik->data_in_reg = -1;
221*0719029cSCorey Minyard     IPMI_KCS_SET_IBF(ik->status_reg, 0);
222*0719029cSCorey Minyard  out_noibf:
223*0719029cSCorey Minyard     return;
224*0719029cSCorey Minyard }
225*0719029cSCorey Minyard 
226*0719029cSCorey Minyard static void ipmi_kcs_handle_rsp(IPMIInterface *ii, uint8_t msg_id,
227*0719029cSCorey Minyard                                 unsigned char *rsp, unsigned int rsp_len)
228*0719029cSCorey Minyard {
229*0719029cSCorey Minyard     IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
230*0719029cSCorey Minyard     IPMIKCS *ik = iic->get_backend_data(ii);
231*0719029cSCorey Minyard 
232*0719029cSCorey Minyard     if (ik->waiting_rsp == msg_id) {
233*0719029cSCorey Minyard         ik->waiting_rsp++;
234*0719029cSCorey Minyard         if (rsp_len > sizeof(ik->outmsg)) {
235*0719029cSCorey Minyard             ik->outmsg[0] = rsp[0];
236*0719029cSCorey Minyard             ik->outmsg[1] = rsp[1];
237*0719029cSCorey Minyard             ik->outmsg[2] = IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES;
238*0719029cSCorey Minyard             ik->outlen = 3;
239*0719029cSCorey Minyard         } else {
240*0719029cSCorey Minyard             memcpy(ik->outmsg, rsp, rsp_len);
241*0719029cSCorey Minyard             ik->outlen = rsp_len;
242*0719029cSCorey Minyard         }
243*0719029cSCorey Minyard         IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_READ_STATE);
244*0719029cSCorey Minyard         ik->data_in_reg = IPMI_KCS_READ_CMD;
245*0719029cSCorey Minyard         ipmi_kcs_signal(ik, ii);
246*0719029cSCorey Minyard     }
247*0719029cSCorey Minyard }
248*0719029cSCorey Minyard 
249*0719029cSCorey Minyard 
250*0719029cSCorey Minyard static uint64_t ipmi_kcs_ioport_read(void *opaque, hwaddr addr, unsigned size)
251*0719029cSCorey Minyard {
252*0719029cSCorey Minyard     IPMIInterface *ii = opaque;
253*0719029cSCorey Minyard     IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
254*0719029cSCorey Minyard     IPMIKCS *ik = iic->get_backend_data(ii);
255*0719029cSCorey Minyard     uint32_t ret;
256*0719029cSCorey Minyard 
257*0719029cSCorey Minyard     switch (addr & 1) {
258*0719029cSCorey Minyard     case 0:
259*0719029cSCorey Minyard         ret = ik->data_out_reg;
260*0719029cSCorey Minyard         IPMI_KCS_SET_OBF(ik->status_reg, 0);
261*0719029cSCorey Minyard         if (ik->obf_irq_set) {
262*0719029cSCorey Minyard             ik->obf_irq_set = 0;
263*0719029cSCorey Minyard             if (!ik->atn_irq_set) {
264*0719029cSCorey Minyard                 qemu_irq_lower(ik->irq);
265*0719029cSCorey Minyard             }
266*0719029cSCorey Minyard         }
267*0719029cSCorey Minyard         break;
268*0719029cSCorey Minyard     case 1:
269*0719029cSCorey Minyard         ret = ik->status_reg;
270*0719029cSCorey Minyard         if (ik->atn_irq_set) {
271*0719029cSCorey Minyard             ik->atn_irq_set = 0;
272*0719029cSCorey Minyard             if (!ik->obf_irq_set) {
273*0719029cSCorey Minyard                 qemu_irq_lower(ik->irq);
274*0719029cSCorey Minyard             }
275*0719029cSCorey Minyard         }
276*0719029cSCorey Minyard         break;
277*0719029cSCorey Minyard     }
278*0719029cSCorey Minyard     return ret;
279*0719029cSCorey Minyard }
280*0719029cSCorey Minyard 
281*0719029cSCorey Minyard static void ipmi_kcs_ioport_write(void *opaque, hwaddr addr, uint64_t val,
282*0719029cSCorey Minyard                                   unsigned size)
283*0719029cSCorey Minyard {
284*0719029cSCorey Minyard     IPMIInterface *ii = opaque;
285*0719029cSCorey Minyard     IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
286*0719029cSCorey Minyard     IPMIKCS *ik = iic->get_backend_data(ii);
287*0719029cSCorey Minyard 
288*0719029cSCorey Minyard     if (IPMI_KCS_GET_IBF(ik->status_reg)) {
289*0719029cSCorey Minyard         return;
290*0719029cSCorey Minyard     }
291*0719029cSCorey Minyard 
292*0719029cSCorey Minyard     switch (addr & 1) {
293*0719029cSCorey Minyard     case 0:
294*0719029cSCorey Minyard         ik->data_in_reg = val;
295*0719029cSCorey Minyard         break;
296*0719029cSCorey Minyard 
297*0719029cSCorey Minyard     case 1:
298*0719029cSCorey Minyard         ik->cmd_reg = val;
299*0719029cSCorey Minyard         break;
300*0719029cSCorey Minyard     }
301*0719029cSCorey Minyard     IPMI_KCS_SET_IBF(ik->status_reg, 1);
302*0719029cSCorey Minyard     ipmi_kcs_signal(ik, ii);
303*0719029cSCorey Minyard }
304*0719029cSCorey Minyard 
305*0719029cSCorey Minyard const MemoryRegionOps ipmi_kcs_io_ops = {
306*0719029cSCorey Minyard     .read = ipmi_kcs_ioport_read,
307*0719029cSCorey Minyard     .write = ipmi_kcs_ioport_write,
308*0719029cSCorey Minyard     .impl = {
309*0719029cSCorey Minyard         .min_access_size = 1,
310*0719029cSCorey Minyard         .max_access_size = 1,
311*0719029cSCorey Minyard     },
312*0719029cSCorey Minyard     .endianness = DEVICE_LITTLE_ENDIAN,
313*0719029cSCorey Minyard };
314*0719029cSCorey Minyard 
315*0719029cSCorey Minyard static void ipmi_kcs_set_atn(IPMIInterface *ii, int val, int irq)
316*0719029cSCorey Minyard {
317*0719029cSCorey Minyard     IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
318*0719029cSCorey Minyard     IPMIKCS *ik = iic->get_backend_data(ii);
319*0719029cSCorey Minyard 
320*0719029cSCorey Minyard     IPMI_KCS_SET_SMS_ATN(ik->status_reg, val);
321*0719029cSCorey Minyard     if (val) {
322*0719029cSCorey Minyard         if (irq && !ik->atn_irq_set && ik->use_irq && ik->irqs_enabled) {
323*0719029cSCorey Minyard             ik->atn_irq_set = 1;
324*0719029cSCorey Minyard             if (!ik->obf_irq_set) {
325*0719029cSCorey Minyard                 qemu_irq_raise(ik->irq);
326*0719029cSCorey Minyard             }
327*0719029cSCorey Minyard         }
328*0719029cSCorey Minyard     } else {
329*0719029cSCorey Minyard         if (ik->atn_irq_set) {
330*0719029cSCorey Minyard             ik->atn_irq_set = 0;
331*0719029cSCorey Minyard             if (!ik->obf_irq_set) {
332*0719029cSCorey Minyard                 qemu_irq_lower(ik->irq);
333*0719029cSCorey Minyard             }
334*0719029cSCorey Minyard         }
335*0719029cSCorey Minyard     }
336*0719029cSCorey Minyard }
337*0719029cSCorey Minyard 
338*0719029cSCorey Minyard static void ipmi_kcs_set_irq_enable(IPMIInterface *ii, int val)
339*0719029cSCorey Minyard {
340*0719029cSCorey Minyard     IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
341*0719029cSCorey Minyard     IPMIKCS *ik = iic->get_backend_data(ii);
342*0719029cSCorey Minyard 
343*0719029cSCorey Minyard     ik->irqs_enabled = val;
344*0719029cSCorey Minyard }
345*0719029cSCorey Minyard 
346*0719029cSCorey Minyard static void ipmi_kcs_init(IPMIInterface *ii, Error **errp)
347*0719029cSCorey Minyard {
348*0719029cSCorey Minyard     IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
349*0719029cSCorey Minyard     IPMIKCS *ik = iic->get_backend_data(ii);
350*0719029cSCorey Minyard 
351*0719029cSCorey Minyard     ik->io_length = 2;
352*0719029cSCorey Minyard     memory_region_init_io(&ik->io, NULL, &ipmi_kcs_io_ops, ii, "ipmi-kcs", 2);
353*0719029cSCorey Minyard }
354*0719029cSCorey Minyard 
355*0719029cSCorey Minyard static void ipmi_kcs_class_init(IPMIInterfaceClass *iic)
356*0719029cSCorey Minyard {
357*0719029cSCorey Minyard     iic->init = ipmi_kcs_init;
358*0719029cSCorey Minyard     iic->set_atn = ipmi_kcs_set_atn;
359*0719029cSCorey Minyard     iic->handle_rsp = ipmi_kcs_handle_rsp;
360*0719029cSCorey Minyard     iic->handle_if_event = ipmi_kcs_handle_event;
361*0719029cSCorey Minyard     iic->set_irq_enable = ipmi_kcs_set_irq_enable;
362*0719029cSCorey Minyard }
363*0719029cSCorey Minyard 
364*0719029cSCorey Minyard 
365*0719029cSCorey Minyard #define TYPE_ISA_IPMI_KCS "isa-ipmi-kcs"
366*0719029cSCorey Minyard #define ISA_IPMI_KCS(obj) OBJECT_CHECK(ISAIPMIKCSDevice, (obj), \
367*0719029cSCorey Minyard                                        TYPE_ISA_IPMI_KCS)
368*0719029cSCorey Minyard 
369*0719029cSCorey Minyard typedef struct ISAIPMIKCSDevice {
370*0719029cSCorey Minyard     ISADevice dev;
371*0719029cSCorey Minyard     int32 isairq;
372*0719029cSCorey Minyard     IPMIKCS kcs;
373*0719029cSCorey Minyard } ISAIPMIKCSDevice;
374*0719029cSCorey Minyard 
375*0719029cSCorey Minyard static void ipmi_isa_realize(DeviceState *dev, Error **errp)
376*0719029cSCorey Minyard {
377*0719029cSCorey Minyard     ISADevice *isadev = ISA_DEVICE(dev);
378*0719029cSCorey Minyard     ISAIPMIKCSDevice *iik = ISA_IPMI_KCS(dev);
379*0719029cSCorey Minyard     IPMIInterface *ii = IPMI_INTERFACE(dev);
380*0719029cSCorey Minyard     IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
381*0719029cSCorey Minyard 
382*0719029cSCorey Minyard     if (!iik->kcs.bmc) {
383*0719029cSCorey Minyard         error_setg(errp, "IPMI device requires a bmc attribute to be set");
384*0719029cSCorey Minyard         return;
385*0719029cSCorey Minyard     }
386*0719029cSCorey Minyard 
387*0719029cSCorey Minyard     iik->kcs.bmc->intf = ii;
388*0719029cSCorey Minyard 
389*0719029cSCorey Minyard     iic->init(ii, errp);
390*0719029cSCorey Minyard     if (*errp)
391*0719029cSCorey Minyard         return;
392*0719029cSCorey Minyard 
393*0719029cSCorey Minyard     if (iik->isairq > 0) {
394*0719029cSCorey Minyard         isa_init_irq(isadev, &iik->kcs.irq, iik->isairq);
395*0719029cSCorey Minyard         iik->kcs.use_irq = 1;
396*0719029cSCorey Minyard     }
397*0719029cSCorey Minyard 
398*0719029cSCorey Minyard     qdev_set_legacy_instance_id(dev, iik->kcs.io_base, iik->kcs.io_length);
399*0719029cSCorey Minyard 
400*0719029cSCorey Minyard     isa_register_ioport(isadev, &iik->kcs.io, iik->kcs.io_base);
401*0719029cSCorey Minyard }
402*0719029cSCorey Minyard 
403*0719029cSCorey Minyard static void isa_ipmi_kcs_init(Object *obj)
404*0719029cSCorey Minyard {
405*0719029cSCorey Minyard     ISAIPMIKCSDevice *iik = ISA_IPMI_KCS(obj);
406*0719029cSCorey Minyard 
407*0719029cSCorey Minyard     ipmi_bmc_find_and_link(obj, (Object **) &iik->kcs.bmc);
408*0719029cSCorey Minyard }
409*0719029cSCorey Minyard 
410*0719029cSCorey Minyard static void *isa_ipmi_kcs_get_backend_data(IPMIInterface *ii)
411*0719029cSCorey Minyard {
412*0719029cSCorey Minyard     ISAIPMIKCSDevice *iik = ISA_IPMI_KCS(ii);
413*0719029cSCorey Minyard 
414*0719029cSCorey Minyard     return &iik->kcs;
415*0719029cSCorey Minyard }
416*0719029cSCorey Minyard 
417*0719029cSCorey Minyard static Property ipmi_isa_properties[] = {
418*0719029cSCorey Minyard     DEFINE_PROP_UINT32("ioport", ISAIPMIKCSDevice, kcs.io_base,  0xca2),
419*0719029cSCorey Minyard     DEFINE_PROP_INT32("irq",   ISAIPMIKCSDevice, isairq,  5),
420*0719029cSCorey Minyard     DEFINE_PROP_END_OF_LIST(),
421*0719029cSCorey Minyard };
422*0719029cSCorey Minyard 
423*0719029cSCorey Minyard static void isa_ipmi_kcs_class_init(ObjectClass *oc, void *data)
424*0719029cSCorey Minyard {
425*0719029cSCorey Minyard     DeviceClass *dc = DEVICE_CLASS(oc);
426*0719029cSCorey Minyard     IPMIInterfaceClass *iic = IPMI_INTERFACE_CLASS(oc);
427*0719029cSCorey Minyard 
428*0719029cSCorey Minyard     dc->realize = ipmi_isa_realize;
429*0719029cSCorey Minyard     dc->props = ipmi_isa_properties;
430*0719029cSCorey Minyard 
431*0719029cSCorey Minyard     iic->get_backend_data = isa_ipmi_kcs_get_backend_data;
432*0719029cSCorey Minyard     ipmi_kcs_class_init(iic);
433*0719029cSCorey Minyard }
434*0719029cSCorey Minyard 
435*0719029cSCorey Minyard static const TypeInfo isa_ipmi_kcs_info = {
436*0719029cSCorey Minyard     .name          = TYPE_ISA_IPMI_KCS,
437*0719029cSCorey Minyard     .parent        = TYPE_ISA_DEVICE,
438*0719029cSCorey Minyard     .instance_size = sizeof(ISAIPMIKCSDevice),
439*0719029cSCorey Minyard     .instance_init = isa_ipmi_kcs_init,
440*0719029cSCorey Minyard     .class_init    = isa_ipmi_kcs_class_init,
441*0719029cSCorey Minyard     .interfaces = (InterfaceInfo[]) {
442*0719029cSCorey Minyard         { TYPE_IPMI_INTERFACE },
443*0719029cSCorey Minyard         { }
444*0719029cSCorey Minyard     }
445*0719029cSCorey Minyard };
446*0719029cSCorey Minyard 
447*0719029cSCorey Minyard static void ipmi_register_types(void)
448*0719029cSCorey Minyard {
449*0719029cSCorey Minyard     type_register_static(&isa_ipmi_kcs_info);
450*0719029cSCorey Minyard }
451*0719029cSCorey Minyard 
452*0719029cSCorey Minyard type_init(ipmi_register_types)
453