xref: /qemu/hw/ipmi/ipmi_kcs.c (revision 019fbfa4bcd2d3a835c241295e22ab2b5b56129b)
10f310cd6SCorey Minyard /*
20f310cd6SCorey Minyard  * QEMU IPMI KCS emulation
30f310cd6SCorey Minyard  *
40f310cd6SCorey Minyard  * Copyright (c) 2015,2017 Corey Minyard, MontaVista Software, LLC
50f310cd6SCorey Minyard  *
60f310cd6SCorey Minyard  * Permission is hereby granted, free of charge, to any person obtaining a copy
70f310cd6SCorey Minyard  * of this software and associated documentation files (the "Software"), to deal
80f310cd6SCorey Minyard  * in the Software without restriction, including without limitation the rights
90f310cd6SCorey Minyard  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
100f310cd6SCorey Minyard  * copies of the Software, and to permit persons to whom the Software is
110f310cd6SCorey Minyard  * furnished to do so, subject to the following conditions:
120f310cd6SCorey Minyard  *
130f310cd6SCorey Minyard  * The above copyright notice and this permission notice shall be included in
140f310cd6SCorey Minyard  * all copies or substantial portions of the Software.
150f310cd6SCorey Minyard  *
160f310cd6SCorey Minyard  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
170f310cd6SCorey Minyard  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
180f310cd6SCorey Minyard  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
190f310cd6SCorey Minyard  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
200f310cd6SCorey Minyard  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
210f310cd6SCorey Minyard  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
220f310cd6SCorey Minyard  * THE SOFTWARE.
230f310cd6SCorey Minyard  */
240f310cd6SCorey Minyard #include "qemu/osdep.h"
250f310cd6SCorey Minyard #include "migration/vmstate.h"
260f310cd6SCorey Minyard #include "qemu/log.h"
270f310cd6SCorey Minyard #include "qapi/error.h"
280f310cd6SCorey Minyard #include "hw/ipmi/ipmi_kcs.h"
290f310cd6SCorey Minyard 
300f310cd6SCorey Minyard #define IPMI_KCS_OBF_BIT        0
310f310cd6SCorey Minyard #define IPMI_KCS_IBF_BIT        1
320f310cd6SCorey Minyard #define IPMI_KCS_SMS_ATN_BIT    2
330f310cd6SCorey Minyard #define IPMI_KCS_CD_BIT         3
340f310cd6SCorey Minyard 
350f310cd6SCorey Minyard #define IPMI_KCS_OBF_MASK          (1 << IPMI_KCS_OBF_BIT)
360f310cd6SCorey Minyard #define IPMI_KCS_GET_OBF(d)        (((d) >> IPMI_KCS_OBF_BIT) & 0x1)
370f310cd6SCorey Minyard #define IPMI_KCS_SET_OBF(d, v)     (d) = (((d) & ~IPMI_KCS_OBF_MASK) | \
380f310cd6SCorey Minyard                                        (((v) & 1) << IPMI_KCS_OBF_BIT))
390f310cd6SCorey Minyard #define IPMI_KCS_IBF_MASK          (1 << IPMI_KCS_IBF_BIT)
400f310cd6SCorey Minyard #define IPMI_KCS_GET_IBF(d)        (((d) >> IPMI_KCS_IBF_BIT) & 0x1)
410f310cd6SCorey Minyard #define IPMI_KCS_SET_IBF(d, v)     (d) = (((d) & ~IPMI_KCS_IBF_MASK) | \
420f310cd6SCorey Minyard                                        (((v) & 1) << IPMI_KCS_IBF_BIT))
430f310cd6SCorey Minyard #define IPMI_KCS_SMS_ATN_MASK      (1 << IPMI_KCS_SMS_ATN_BIT)
440f310cd6SCorey Minyard #define IPMI_KCS_GET_SMS_ATN(d)    (((d) >> IPMI_KCS_SMS_ATN_BIT) & 0x1)
450f310cd6SCorey Minyard #define IPMI_KCS_SET_SMS_ATN(d, v) (d) = (((d) & ~IPMI_KCS_SMS_ATN_MASK) | \
460f310cd6SCorey Minyard                                        (((v) & 1) << IPMI_KCS_SMS_ATN_BIT))
470f310cd6SCorey Minyard #define IPMI_KCS_CD_MASK           (1 << IPMI_KCS_CD_BIT)
480f310cd6SCorey Minyard #define IPMI_KCS_GET_CD(d)         (((d) >> IPMI_KCS_CD_BIT) & 0x1)
490f310cd6SCorey Minyard #define IPMI_KCS_SET_CD(d, v)      (d) = (((d) & ~IPMI_KCS_CD_MASK) | \
500f310cd6SCorey Minyard                                        (((v) & 1) << IPMI_KCS_CD_BIT))
510f310cd6SCorey Minyard 
520f310cd6SCorey Minyard #define IPMI_KCS_IDLE_STATE        0
530f310cd6SCorey Minyard #define IPMI_KCS_READ_STATE        1
540f310cd6SCorey Minyard #define IPMI_KCS_WRITE_STATE       2
550f310cd6SCorey Minyard #define IPMI_KCS_ERROR_STATE       3
560f310cd6SCorey Minyard 
570f310cd6SCorey Minyard #define IPMI_KCS_GET_STATE(d)    (((d) >> 6) & 0x3)
580f310cd6SCorey Minyard #define IPMI_KCS_SET_STATE(d, v) ((d) = ((d) & ~0xc0) | (((v) & 0x3) << 6))
590f310cd6SCorey Minyard 
600f310cd6SCorey Minyard #define IPMI_KCS_ABORT_STATUS_CMD       0x60
610f310cd6SCorey Minyard #define IPMI_KCS_WRITE_START_CMD        0x61
620f310cd6SCorey Minyard #define IPMI_KCS_WRITE_END_CMD          0x62
630f310cd6SCorey Minyard #define IPMI_KCS_READ_CMD               0x68
640f310cd6SCorey Minyard 
650f310cd6SCorey Minyard #define IPMI_KCS_STATUS_NO_ERR          0x00
660f310cd6SCorey Minyard #define IPMI_KCS_STATUS_ABORTED_ERR     0x01
670f310cd6SCorey Minyard #define IPMI_KCS_STATUS_BAD_CC_ERR      0x02
680f310cd6SCorey Minyard #define IPMI_KCS_STATUS_LENGTH_ERR      0x06
690f310cd6SCorey Minyard 
ipmi_kcs_raise_irq(IPMIKCS * ik)700f310cd6SCorey Minyard static void ipmi_kcs_raise_irq(IPMIKCS *ik)
710f310cd6SCorey Minyard {
720f310cd6SCorey Minyard     if (ik->use_irq && ik->irqs_enabled && ik->raise_irq) {
730f310cd6SCorey Minyard         ik->raise_irq(ik);
740f310cd6SCorey Minyard     }
750f310cd6SCorey Minyard }
760f310cd6SCorey Minyard 
ipmi_kcs_lower_irq(IPMIKCS * ik)770f310cd6SCorey Minyard static void ipmi_kcs_lower_irq(IPMIKCS *ik)
780f310cd6SCorey Minyard {
790f310cd6SCorey Minyard     if (ik->lower_irq) {
800f310cd6SCorey Minyard         ik->lower_irq(ik);
810f310cd6SCorey Minyard     }
820f310cd6SCorey Minyard }
830f310cd6SCorey Minyard 
840f310cd6SCorey Minyard #define SET_OBF() \
850f310cd6SCorey Minyard     do {                                                                      \
860f310cd6SCorey Minyard         IPMI_KCS_SET_OBF(ik->status_reg, 1);                                  \
870f310cd6SCorey Minyard         if (!ik->obf_irq_set) {                                               \
880f310cd6SCorey Minyard             ik->obf_irq_set = 1;                                              \
890f310cd6SCorey Minyard             if (!ik->atn_irq_set) {                                           \
900f310cd6SCorey Minyard                 ipmi_kcs_raise_irq(ik);                                  \
910f310cd6SCorey Minyard             }                                                                 \
920f310cd6SCorey Minyard         }                                                                     \
930f310cd6SCorey Minyard     } while (0)
940f310cd6SCorey Minyard 
ipmi_kcs_signal(IPMIKCS * ik,IPMIInterface * ii)950f310cd6SCorey Minyard static void ipmi_kcs_signal(IPMIKCS *ik, IPMIInterface *ii)
960f310cd6SCorey Minyard {
970f310cd6SCorey Minyard     IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
980f310cd6SCorey Minyard 
990f310cd6SCorey Minyard     ik->do_wake = 1;
1000f310cd6SCorey Minyard     while (ik->do_wake) {
1010f310cd6SCorey Minyard         ik->do_wake = 0;
1020f310cd6SCorey Minyard         iic->handle_if_event(ii);
1030f310cd6SCorey Minyard     }
1040f310cd6SCorey Minyard }
1050f310cd6SCorey Minyard 
ipmi_kcs_handle_event(IPMIInterface * ii)1060f310cd6SCorey Minyard static void ipmi_kcs_handle_event(IPMIInterface *ii)
1070f310cd6SCorey Minyard {
1080f310cd6SCorey Minyard     IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
1090f310cd6SCorey Minyard     IPMIKCS *ik = iic->get_backend_data(ii);
1100f310cd6SCorey Minyard 
1110f310cd6SCorey Minyard     if (ik->cmd_reg == IPMI_KCS_ABORT_STATUS_CMD) {
1120f310cd6SCorey Minyard         if (IPMI_KCS_GET_STATE(ik->status_reg) != IPMI_KCS_ERROR_STATE) {
1130f310cd6SCorey Minyard             ik->waiting_rsp++; /* Invalidate the message */
1140f310cd6SCorey Minyard             ik->outmsg[0] = IPMI_KCS_STATUS_ABORTED_ERR;
1150f310cd6SCorey Minyard             ik->outlen = 1;
1160f310cd6SCorey Minyard             ik->outpos = 0;
1170f310cd6SCorey Minyard             IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_ERROR_STATE);
1180f310cd6SCorey Minyard             SET_OBF();
1190f310cd6SCorey Minyard         }
1200f310cd6SCorey Minyard         goto out;
1210f310cd6SCorey Minyard     }
1220f310cd6SCorey Minyard 
1230f310cd6SCorey Minyard     switch (IPMI_KCS_GET_STATE(ik->status_reg)) {
1240f310cd6SCorey Minyard     case IPMI_KCS_IDLE_STATE:
1250f310cd6SCorey Minyard         if (ik->cmd_reg == IPMI_KCS_WRITE_START_CMD) {
1260f310cd6SCorey Minyard             IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_WRITE_STATE);
1270f310cd6SCorey Minyard             ik->cmd_reg = -1;
1280f310cd6SCorey Minyard             ik->write_end = 0;
1290f310cd6SCorey Minyard             ik->inlen = 0;
1300f310cd6SCorey Minyard             SET_OBF();
1310f310cd6SCorey Minyard         }
1320f310cd6SCorey Minyard         break;
1330f310cd6SCorey Minyard 
1340f310cd6SCorey Minyard     case IPMI_KCS_READ_STATE:
1350f310cd6SCorey Minyard     handle_read:
1360f310cd6SCorey Minyard         if (ik->outpos >= ik->outlen) {
1370f310cd6SCorey Minyard             IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_IDLE_STATE);
1380f310cd6SCorey Minyard             SET_OBF();
1390f310cd6SCorey Minyard         } else if (ik->data_in_reg == IPMI_KCS_READ_CMD) {
1400f310cd6SCorey Minyard             ik->data_out_reg = ik->outmsg[ik->outpos];
1410f310cd6SCorey Minyard             ik->outpos++;
1420f310cd6SCorey Minyard             SET_OBF();
1430f310cd6SCorey Minyard         } else {
1440f310cd6SCorey Minyard             ik->outmsg[0] = IPMI_KCS_STATUS_BAD_CC_ERR;
1450f310cd6SCorey Minyard             ik->outlen = 1;
1460f310cd6SCorey Minyard             ik->outpos = 0;
1470f310cd6SCorey Minyard             IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_ERROR_STATE);
1480f310cd6SCorey Minyard             SET_OBF();
1490f310cd6SCorey Minyard             goto out;
1500f310cd6SCorey Minyard         }
1510f310cd6SCorey Minyard         break;
1520f310cd6SCorey Minyard 
1530f310cd6SCorey Minyard     case IPMI_KCS_WRITE_STATE:
1540f310cd6SCorey Minyard         if (ik->data_in_reg != -1) {
1550f310cd6SCorey Minyard             /*
1560f310cd6SCorey Minyard              * Don't worry about input overrun here, that will be
1570f310cd6SCorey Minyard              * handled in the BMC.
1580f310cd6SCorey Minyard              */
1590f310cd6SCorey Minyard             if (ik->inlen < sizeof(ik->inmsg)) {
1600f310cd6SCorey Minyard                 ik->inmsg[ik->inlen] = ik->data_in_reg;
1610f310cd6SCorey Minyard             }
1620f310cd6SCorey Minyard             ik->inlen++;
1630f310cd6SCorey Minyard         }
1640f310cd6SCorey Minyard         if (ik->write_end) {
1650f310cd6SCorey Minyard             IPMIBmcClass *bk = IPMI_BMC_GET_CLASS(ik->bmc);
1660f310cd6SCorey Minyard             ik->outlen = 0;
1670f310cd6SCorey Minyard             ik->write_end = 0;
1680f310cd6SCorey Minyard             ik->outpos = 0;
1690f310cd6SCorey Minyard             bk->handle_command(ik->bmc, ik->inmsg, ik->inlen, sizeof(ik->inmsg),
1700f310cd6SCorey Minyard                                ik->waiting_rsp);
171*abb55b1aSMarkus Armbruster             return;
1720f310cd6SCorey Minyard         } else if (ik->cmd_reg == IPMI_KCS_WRITE_END_CMD) {
1730f310cd6SCorey Minyard             ik->cmd_reg = -1;
1740f310cd6SCorey Minyard             ik->write_end = 1;
1750f310cd6SCorey Minyard         }
1760f310cd6SCorey Minyard         SET_OBF();
1770f310cd6SCorey Minyard         break;
1780f310cd6SCorey Minyard 
1790f310cd6SCorey Minyard     case IPMI_KCS_ERROR_STATE:
1800f310cd6SCorey Minyard         if (ik->data_in_reg != -1) {
1810f310cd6SCorey Minyard             IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_READ_STATE);
1820f310cd6SCorey Minyard             ik->data_in_reg = IPMI_KCS_READ_CMD;
1830f310cd6SCorey Minyard             goto handle_read;
1840f310cd6SCorey Minyard         }
1850f310cd6SCorey Minyard         break;
1860f310cd6SCorey Minyard     }
1870f310cd6SCorey Minyard 
1880f310cd6SCorey Minyard     if (ik->cmd_reg != -1) {
1890f310cd6SCorey Minyard         /* Got an invalid command */
1900f310cd6SCorey Minyard         ik->outmsg[0] = IPMI_KCS_STATUS_BAD_CC_ERR;
1910f310cd6SCorey Minyard         ik->outlen = 1;
1920f310cd6SCorey Minyard         ik->outpos = 0;
1930f310cd6SCorey Minyard         IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_ERROR_STATE);
1940f310cd6SCorey Minyard     }
1950f310cd6SCorey Minyard 
1960f310cd6SCorey Minyard  out:
1970f310cd6SCorey Minyard     ik->cmd_reg = -1;
1980f310cd6SCorey Minyard     ik->data_in_reg = -1;
1990f310cd6SCorey Minyard     IPMI_KCS_SET_IBF(ik->status_reg, 0);
2000f310cd6SCorey Minyard }
2010f310cd6SCorey Minyard 
ipmi_kcs_handle_rsp(IPMIInterface * ii,uint8_t msg_id,unsigned char * rsp,unsigned int rsp_len)2020f310cd6SCorey Minyard static void ipmi_kcs_handle_rsp(IPMIInterface *ii, uint8_t msg_id,
2030f310cd6SCorey Minyard                                 unsigned char *rsp, unsigned int rsp_len)
2040f310cd6SCorey Minyard {
2050f310cd6SCorey Minyard     IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
2060f310cd6SCorey Minyard     IPMIKCS *ik = iic->get_backend_data(ii);
2070f310cd6SCorey Minyard 
2080f310cd6SCorey Minyard     if (ik->waiting_rsp == msg_id) {
2090f310cd6SCorey Minyard         ik->waiting_rsp++;
2100f310cd6SCorey Minyard         if (rsp_len > sizeof(ik->outmsg)) {
2110f310cd6SCorey Minyard             ik->outmsg[0] = rsp[0];
2120f310cd6SCorey Minyard             ik->outmsg[1] = rsp[1];
2130f310cd6SCorey Minyard             ik->outmsg[2] = IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES;
2140f310cd6SCorey Minyard             ik->outlen = 3;
2150f310cd6SCorey Minyard         } else {
2160f310cd6SCorey Minyard             memcpy(ik->outmsg, rsp, rsp_len);
2170f310cd6SCorey Minyard             ik->outlen = rsp_len;
2180f310cd6SCorey Minyard         }
2190f310cd6SCorey Minyard         IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_READ_STATE);
2200f310cd6SCorey Minyard         ik->data_in_reg = IPMI_KCS_READ_CMD;
2210f310cd6SCorey Minyard         ipmi_kcs_signal(ik, ii);
2220f310cd6SCorey Minyard     }
2230f310cd6SCorey Minyard }
2240f310cd6SCorey Minyard 
2250f310cd6SCorey Minyard 
ipmi_kcs_ioport_read(void * opaque,hwaddr addr,unsigned size)2260f310cd6SCorey Minyard static uint64_t ipmi_kcs_ioport_read(void *opaque, hwaddr addr, unsigned size)
2270f310cd6SCorey Minyard {
2280f310cd6SCorey Minyard     IPMIInterface *ii = opaque;
2290f310cd6SCorey Minyard     IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
2300f310cd6SCorey Minyard     IPMIKCS *ik = iic->get_backend_data(ii);
2310f310cd6SCorey Minyard     uint32_t ret;
2320f310cd6SCorey Minyard 
23379d29a9dSCorey Minyard     switch (addr & ik->size_mask) {
2340f310cd6SCorey Minyard     case 0:
2350f310cd6SCorey Minyard         ret = ik->data_out_reg;
2360f310cd6SCorey Minyard         IPMI_KCS_SET_OBF(ik->status_reg, 0);
2370f310cd6SCorey Minyard         if (ik->obf_irq_set) {
2380f310cd6SCorey Minyard             ik->obf_irq_set = 0;
2390f310cd6SCorey Minyard             if (!ik->atn_irq_set) {
2400f310cd6SCorey Minyard                 ipmi_kcs_lower_irq(ik);
2410f310cd6SCorey Minyard             }
2420f310cd6SCorey Minyard         }
2430f310cd6SCorey Minyard         break;
24479d29a9dSCorey Minyard 
2450f310cd6SCorey Minyard     case 1:
2460f310cd6SCorey Minyard         ret = ik->status_reg;
2470f310cd6SCorey Minyard         if (ik->atn_irq_set) {
2480f310cd6SCorey Minyard             ik->atn_irq_set = 0;
2490f310cd6SCorey Minyard             if (!ik->obf_irq_set) {
2500f310cd6SCorey Minyard                 ipmi_kcs_lower_irq(ik);
2510f310cd6SCorey Minyard             }
2520f310cd6SCorey Minyard         }
2530f310cd6SCorey Minyard         break;
25479d29a9dSCorey Minyard 
25579d29a9dSCorey Minyard     default:
25679d29a9dSCorey Minyard         ret = 0xff;
2570f310cd6SCorey Minyard     }
2580f310cd6SCorey Minyard     return ret;
2590f310cd6SCorey Minyard }
2600f310cd6SCorey Minyard 
ipmi_kcs_ioport_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)2610f310cd6SCorey Minyard static void ipmi_kcs_ioport_write(void *opaque, hwaddr addr, uint64_t val,
2620f310cd6SCorey Minyard                                   unsigned size)
2630f310cd6SCorey Minyard {
2640f310cd6SCorey Minyard     IPMIInterface *ii = opaque;
2650f310cd6SCorey Minyard     IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
2660f310cd6SCorey Minyard     IPMIKCS *ik = iic->get_backend_data(ii);
2670f310cd6SCorey Minyard 
2680f310cd6SCorey Minyard     if (IPMI_KCS_GET_IBF(ik->status_reg)) {
2690f310cd6SCorey Minyard         return;
2700f310cd6SCorey Minyard     }
2710f310cd6SCorey Minyard 
27279d29a9dSCorey Minyard     switch (addr & ik->size_mask) {
2730f310cd6SCorey Minyard     case 0:
2740f310cd6SCorey Minyard         ik->data_in_reg = val;
2750f310cd6SCorey Minyard         break;
2760f310cd6SCorey Minyard 
2770f310cd6SCorey Minyard     case 1:
2780f310cd6SCorey Minyard         ik->cmd_reg = val;
2790f310cd6SCorey Minyard         break;
28079d29a9dSCorey Minyard 
28179d29a9dSCorey Minyard     default:
28279d29a9dSCorey Minyard         /* Ignore. */
28379d29a9dSCorey Minyard         break;
2840f310cd6SCorey Minyard     }
2850f310cd6SCorey Minyard     IPMI_KCS_SET_IBF(ik->status_reg, 1);
2860f310cd6SCorey Minyard     ipmi_kcs_signal(ik, ii);
2870f310cd6SCorey Minyard }
2880f310cd6SCorey Minyard 
2890f310cd6SCorey Minyard const MemoryRegionOps ipmi_kcs_io_ops = {
2900f310cd6SCorey Minyard     .read = ipmi_kcs_ioport_read,
2910f310cd6SCorey Minyard     .write = ipmi_kcs_ioport_write,
2920f310cd6SCorey Minyard     .impl = {
2930f310cd6SCorey Minyard         .min_access_size = 1,
2940f310cd6SCorey Minyard         .max_access_size = 1,
2950f310cd6SCorey Minyard     },
2960f310cd6SCorey Minyard     .endianness = DEVICE_LITTLE_ENDIAN,
2970f310cd6SCorey Minyard };
2980f310cd6SCorey Minyard 
ipmi_kcs_set_atn(IPMIInterface * ii,int val,int irq)2990f310cd6SCorey Minyard static void ipmi_kcs_set_atn(IPMIInterface *ii, int val, int irq)
3000f310cd6SCorey Minyard {
3010f310cd6SCorey Minyard     IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
3020f310cd6SCorey Minyard     IPMIKCS *ik = iic->get_backend_data(ii);
3030f310cd6SCorey Minyard 
3040f310cd6SCorey Minyard     IPMI_KCS_SET_SMS_ATN(ik->status_reg, val);
3050f310cd6SCorey Minyard     if (val) {
3060f310cd6SCorey Minyard         if (irq && !ik->atn_irq_set) {
3070f310cd6SCorey Minyard             ik->atn_irq_set = 1;
3080f310cd6SCorey Minyard             if (!ik->obf_irq_set) {
3090f310cd6SCorey Minyard                 ipmi_kcs_raise_irq(ik);
3100f310cd6SCorey Minyard             }
3110f310cd6SCorey Minyard         }
3120f310cd6SCorey Minyard     } else {
3130f310cd6SCorey Minyard         if (ik->atn_irq_set) {
3140f310cd6SCorey Minyard             ik->atn_irq_set = 0;
3150f310cd6SCorey Minyard             if (!ik->obf_irq_set) {
3160f310cd6SCorey Minyard                 ipmi_kcs_lower_irq(ik);
3170f310cd6SCorey Minyard             }
3180f310cd6SCorey Minyard         }
3190f310cd6SCorey Minyard     }
3200f310cd6SCorey Minyard }
3210f310cd6SCorey Minyard 
ipmi_kcs_set_irq_enable(IPMIInterface * ii,int val)3220f310cd6SCorey Minyard static void ipmi_kcs_set_irq_enable(IPMIInterface *ii, int val)
3230f310cd6SCorey Minyard {
3240f310cd6SCorey Minyard     IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
3250f310cd6SCorey Minyard     IPMIKCS *ik = iic->get_backend_data(ii);
3260f310cd6SCorey Minyard 
3270f310cd6SCorey Minyard     ik->irqs_enabled = val;
3280f310cd6SCorey Minyard }
3290f310cd6SCorey Minyard 
33079d29a9dSCorey Minyard /* min_size must be a power of 2. */
ipmi_kcs_init(IPMIInterface * ii,unsigned int min_size,Error ** errp)33179d29a9dSCorey Minyard static void ipmi_kcs_init(IPMIInterface *ii, unsigned int min_size,
33279d29a9dSCorey Minyard                           Error **errp)
3330f310cd6SCorey Minyard {
3340f310cd6SCorey Minyard     IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
3350f310cd6SCorey Minyard     IPMIKCS *ik = iic->get_backend_data(ii);
3360f310cd6SCorey Minyard 
33779d29a9dSCorey Minyard     if (min_size == 0) {
33879d29a9dSCorey Minyard         min_size = 2;
33979d29a9dSCorey Minyard     }
34079d29a9dSCorey Minyard     ik->size_mask = min_size - 1;
3410f310cd6SCorey Minyard     ik->io_length = 2;
34279d29a9dSCorey Minyard     memory_region_init_io(&ik->io, NULL, &ipmi_kcs_io_ops, ii, "ipmi-kcs",
34379d29a9dSCorey Minyard                           min_size);
3440f310cd6SCorey Minyard }
3450f310cd6SCorey Minyard 
ipmi_kcs_vmstate_post_load(void * opaque,int version)3460f310cd6SCorey Minyard int ipmi_kcs_vmstate_post_load(void *opaque, int version)
3470f310cd6SCorey Minyard {
3480f310cd6SCorey Minyard     IPMIKCS *ik = opaque;
3490f310cd6SCorey Minyard 
3500f310cd6SCorey Minyard     /* Make sure all the values are sane. */
3510f310cd6SCorey Minyard     if (ik->outpos >= MAX_IPMI_MSG_SIZE || ik->outlen >= MAX_IPMI_MSG_SIZE ||
3520f310cd6SCorey Minyard         ik->outpos >= ik->outlen) {
3530f310cd6SCorey Minyard         qemu_log_mask(LOG_GUEST_ERROR,
3540f310cd6SCorey Minyard                       "ipmi:kcs: vmstate transfer received bad out values: %d %d\n",
3550f310cd6SCorey Minyard                       ik->outpos, ik->outlen);
3560f310cd6SCorey Minyard         ik->outpos = 0;
3570f310cd6SCorey Minyard         ik->outlen = 0;
3580f310cd6SCorey Minyard     }
3590f310cd6SCorey Minyard 
3600f310cd6SCorey Minyard     if (ik->inlen >= MAX_IPMI_MSG_SIZE) {
3610f310cd6SCorey Minyard         qemu_log_mask(LOG_GUEST_ERROR,
3620f310cd6SCorey Minyard                       "ipmi:kcs: vmstate transfer received bad in value: %d\n",
3630f310cd6SCorey Minyard                       ik->inlen);
3640f310cd6SCorey Minyard         ik->inlen = 0;
3650f310cd6SCorey Minyard     }
3660f310cd6SCorey Minyard 
3670f310cd6SCorey Minyard     return 0;
3680f310cd6SCorey Minyard }
3690f310cd6SCorey Minyard 
vmstate_kcs_before_version2(void * opaque,int version)3700f310cd6SCorey Minyard static bool vmstate_kcs_before_version2(void *opaque, int version)
3710f310cd6SCorey Minyard {
3720f310cd6SCorey Minyard     return version <= 1;
3730f310cd6SCorey Minyard }
3740f310cd6SCorey Minyard 
3750f310cd6SCorey Minyard const VMStateDescription vmstate_IPMIKCS = {
3760f310cd6SCorey Minyard     .name = TYPE_IPMI_INTERFACE_PREFIX "kcs",
3770f310cd6SCorey Minyard     .version_id = 2,
3780f310cd6SCorey Minyard     .minimum_version_id = 1,
3790f310cd6SCorey Minyard     .post_load = ipmi_kcs_vmstate_post_load,
38009c6ac6dSRichard Henderson     .fields = (const VMStateField[]) {
3810f310cd6SCorey Minyard         VMSTATE_BOOL(obf_irq_set, IPMIKCS),
3820f310cd6SCorey Minyard         VMSTATE_BOOL(atn_irq_set, IPMIKCS),
3830f310cd6SCorey Minyard         VMSTATE_UNUSED_TEST(vmstate_kcs_before_version2, 1), /* Was use_irq */
3840f310cd6SCorey Minyard         VMSTATE_BOOL(irqs_enabled, IPMIKCS),
3850f310cd6SCorey Minyard         VMSTATE_UINT32(outpos, IPMIKCS),
3860f310cd6SCorey Minyard         VMSTATE_UINT32_V(outlen, IPMIKCS, 2),
3870f310cd6SCorey Minyard         VMSTATE_UINT8_ARRAY(outmsg, IPMIKCS, MAX_IPMI_MSG_SIZE),
3880f310cd6SCorey Minyard         VMSTATE_UINT32_V(inlen, IPMIKCS, 2),
3890f310cd6SCorey Minyard         VMSTATE_UINT8_ARRAY(inmsg, IPMIKCS, MAX_IPMI_MSG_SIZE),
3900f310cd6SCorey Minyard         VMSTATE_BOOL(write_end, IPMIKCS),
3910f310cd6SCorey Minyard         VMSTATE_UINT8(status_reg, IPMIKCS),
3920f310cd6SCorey Minyard         VMSTATE_UINT8(data_out_reg, IPMIKCS),
3930f310cd6SCorey Minyard         VMSTATE_INT16(data_in_reg, IPMIKCS),
3940f310cd6SCorey Minyard         VMSTATE_INT16(cmd_reg, IPMIKCS),
3950f310cd6SCorey Minyard         VMSTATE_UINT8(waiting_rsp, IPMIKCS),
3960f310cd6SCorey Minyard         VMSTATE_END_OF_LIST()
3970f310cd6SCorey Minyard     }
3980f310cd6SCorey Minyard };
3990f310cd6SCorey Minyard 
ipmi_kcs_get_fwinfo(IPMIKCS * ik,IPMIFwInfo * info)4000f310cd6SCorey Minyard void ipmi_kcs_get_fwinfo(IPMIKCS *ik, IPMIFwInfo *info)
4010f310cd6SCorey Minyard {
4020f310cd6SCorey Minyard     info->interface_name = "kcs";
4030f310cd6SCorey Minyard     info->interface_type = IPMI_SMBIOS_KCS;
4040f310cd6SCorey Minyard     info->ipmi_spec_major_revision = 2;
4050f310cd6SCorey Minyard     info->ipmi_spec_minor_revision = 0;
4067f9e7af4SNicholas Piggin     info->ipmi_channel_protocol = IPMI_CHANNEL_PROTOCOL_KCS;
4070f310cd6SCorey Minyard     info->base_address = ik->io_base;
4080f310cd6SCorey Minyard     info->i2c_slave_address = ik->bmc->slave_addr;
4090f310cd6SCorey Minyard     info->register_length = ik->io_length;
4100f310cd6SCorey Minyard     info->register_spacing = 1;
4110f310cd6SCorey Minyard     info->memspace = IPMI_MEMSPACE_IO;
4120f310cd6SCorey Minyard     info->irq_type = IPMI_LEVEL_IRQ;
4130f310cd6SCorey Minyard }
4140f310cd6SCorey Minyard 
ipmi_kcs_class_init(IPMIInterfaceClass * iic)4150f310cd6SCorey Minyard void ipmi_kcs_class_init(IPMIInterfaceClass *iic)
4160f310cd6SCorey Minyard {
4170f310cd6SCorey Minyard     iic->init = ipmi_kcs_init;
4180f310cd6SCorey Minyard     iic->set_atn = ipmi_kcs_set_atn;
4190f310cd6SCorey Minyard     iic->handle_rsp = ipmi_kcs_handle_rsp;
4200f310cd6SCorey Minyard     iic->handle_if_event = ipmi_kcs_handle_event;
4210f310cd6SCorey Minyard     iic->set_irq_enable = ipmi_kcs_set_irq_enable;
4220f310cd6SCorey Minyard }
423