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 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 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 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 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); 1710f310cd6SCorey Minyard goto out_noibf; 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 out_noibf: 2010f310cd6SCorey Minyard return; 2020f310cd6SCorey Minyard } 2030f310cd6SCorey Minyard 2040f310cd6SCorey Minyard static void ipmi_kcs_handle_rsp(IPMIInterface *ii, uint8_t msg_id, 2050f310cd6SCorey Minyard unsigned char *rsp, unsigned int rsp_len) 2060f310cd6SCorey Minyard { 2070f310cd6SCorey Minyard IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii); 2080f310cd6SCorey Minyard IPMIKCS *ik = iic->get_backend_data(ii); 2090f310cd6SCorey Minyard 2100f310cd6SCorey Minyard if (ik->waiting_rsp == msg_id) { 2110f310cd6SCorey Minyard ik->waiting_rsp++; 2120f310cd6SCorey Minyard if (rsp_len > sizeof(ik->outmsg)) { 2130f310cd6SCorey Minyard ik->outmsg[0] = rsp[0]; 2140f310cd6SCorey Minyard ik->outmsg[1] = rsp[1]; 2150f310cd6SCorey Minyard ik->outmsg[2] = IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES; 2160f310cd6SCorey Minyard ik->outlen = 3; 2170f310cd6SCorey Minyard } else { 2180f310cd6SCorey Minyard memcpy(ik->outmsg, rsp, rsp_len); 2190f310cd6SCorey Minyard ik->outlen = rsp_len; 2200f310cd6SCorey Minyard } 2210f310cd6SCorey Minyard IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_READ_STATE); 2220f310cd6SCorey Minyard ik->data_in_reg = IPMI_KCS_READ_CMD; 2230f310cd6SCorey Minyard ipmi_kcs_signal(ik, ii); 2240f310cd6SCorey Minyard } 2250f310cd6SCorey Minyard } 2260f310cd6SCorey Minyard 2270f310cd6SCorey Minyard 2280f310cd6SCorey Minyard static uint64_t ipmi_kcs_ioport_read(void *opaque, hwaddr addr, unsigned size) 2290f310cd6SCorey Minyard { 2300f310cd6SCorey Minyard IPMIInterface *ii = opaque; 2310f310cd6SCorey Minyard IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii); 2320f310cd6SCorey Minyard IPMIKCS *ik = iic->get_backend_data(ii); 2330f310cd6SCorey Minyard uint32_t ret; 2340f310cd6SCorey Minyard 235*79d29a9dSCorey Minyard switch (addr & ik->size_mask) { 2360f310cd6SCorey Minyard case 0: 2370f310cd6SCorey Minyard ret = ik->data_out_reg; 2380f310cd6SCorey Minyard IPMI_KCS_SET_OBF(ik->status_reg, 0); 2390f310cd6SCorey Minyard if (ik->obf_irq_set) { 2400f310cd6SCorey Minyard ik->obf_irq_set = 0; 2410f310cd6SCorey Minyard if (!ik->atn_irq_set) { 2420f310cd6SCorey Minyard ipmi_kcs_lower_irq(ik); 2430f310cd6SCorey Minyard } 2440f310cd6SCorey Minyard } 2450f310cd6SCorey Minyard break; 246*79d29a9dSCorey Minyard 2470f310cd6SCorey Minyard case 1: 2480f310cd6SCorey Minyard ret = ik->status_reg; 2490f310cd6SCorey Minyard if (ik->atn_irq_set) { 2500f310cd6SCorey Minyard ik->atn_irq_set = 0; 2510f310cd6SCorey Minyard if (!ik->obf_irq_set) { 2520f310cd6SCorey Minyard ipmi_kcs_lower_irq(ik); 2530f310cd6SCorey Minyard } 2540f310cd6SCorey Minyard } 2550f310cd6SCorey Minyard break; 256*79d29a9dSCorey Minyard 257*79d29a9dSCorey Minyard default: 258*79d29a9dSCorey Minyard ret = 0xff; 2590f310cd6SCorey Minyard } 2600f310cd6SCorey Minyard return ret; 2610f310cd6SCorey Minyard } 2620f310cd6SCorey Minyard 2630f310cd6SCorey Minyard static void ipmi_kcs_ioport_write(void *opaque, hwaddr addr, uint64_t val, 2640f310cd6SCorey Minyard unsigned size) 2650f310cd6SCorey Minyard { 2660f310cd6SCorey Minyard IPMIInterface *ii = opaque; 2670f310cd6SCorey Minyard IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii); 2680f310cd6SCorey Minyard IPMIKCS *ik = iic->get_backend_data(ii); 2690f310cd6SCorey Minyard 2700f310cd6SCorey Minyard if (IPMI_KCS_GET_IBF(ik->status_reg)) { 2710f310cd6SCorey Minyard return; 2720f310cd6SCorey Minyard } 2730f310cd6SCorey Minyard 274*79d29a9dSCorey Minyard switch (addr & ik->size_mask) { 2750f310cd6SCorey Minyard case 0: 2760f310cd6SCorey Minyard ik->data_in_reg = val; 2770f310cd6SCorey Minyard break; 2780f310cd6SCorey Minyard 2790f310cd6SCorey Minyard case 1: 2800f310cd6SCorey Minyard ik->cmd_reg = val; 2810f310cd6SCorey Minyard break; 282*79d29a9dSCorey Minyard 283*79d29a9dSCorey Minyard default: 284*79d29a9dSCorey Minyard /* Ignore. */ 285*79d29a9dSCorey Minyard break; 2860f310cd6SCorey Minyard } 2870f310cd6SCorey Minyard IPMI_KCS_SET_IBF(ik->status_reg, 1); 2880f310cd6SCorey Minyard ipmi_kcs_signal(ik, ii); 2890f310cd6SCorey Minyard } 2900f310cd6SCorey Minyard 2910f310cd6SCorey Minyard const MemoryRegionOps ipmi_kcs_io_ops = { 2920f310cd6SCorey Minyard .read = ipmi_kcs_ioport_read, 2930f310cd6SCorey Minyard .write = ipmi_kcs_ioport_write, 2940f310cd6SCorey Minyard .impl = { 2950f310cd6SCorey Minyard .min_access_size = 1, 2960f310cd6SCorey Minyard .max_access_size = 1, 2970f310cd6SCorey Minyard }, 2980f310cd6SCorey Minyard .endianness = DEVICE_LITTLE_ENDIAN, 2990f310cd6SCorey Minyard }; 3000f310cd6SCorey Minyard 3010f310cd6SCorey Minyard static void ipmi_kcs_set_atn(IPMIInterface *ii, int val, int irq) 3020f310cd6SCorey Minyard { 3030f310cd6SCorey Minyard IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii); 3040f310cd6SCorey Minyard IPMIKCS *ik = iic->get_backend_data(ii); 3050f310cd6SCorey Minyard 3060f310cd6SCorey Minyard IPMI_KCS_SET_SMS_ATN(ik->status_reg, val); 3070f310cd6SCorey Minyard if (val) { 3080f310cd6SCorey Minyard if (irq && !ik->atn_irq_set) { 3090f310cd6SCorey Minyard ik->atn_irq_set = 1; 3100f310cd6SCorey Minyard if (!ik->obf_irq_set) { 3110f310cd6SCorey Minyard ipmi_kcs_raise_irq(ik); 3120f310cd6SCorey Minyard } 3130f310cd6SCorey Minyard } 3140f310cd6SCorey Minyard } else { 3150f310cd6SCorey Minyard if (ik->atn_irq_set) { 3160f310cd6SCorey Minyard ik->atn_irq_set = 0; 3170f310cd6SCorey Minyard if (!ik->obf_irq_set) { 3180f310cd6SCorey Minyard ipmi_kcs_lower_irq(ik); 3190f310cd6SCorey Minyard } 3200f310cd6SCorey Minyard } 3210f310cd6SCorey Minyard } 3220f310cd6SCorey Minyard } 3230f310cd6SCorey Minyard 3240f310cd6SCorey Minyard static void ipmi_kcs_set_irq_enable(IPMIInterface *ii, int val) 3250f310cd6SCorey Minyard { 3260f310cd6SCorey Minyard IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii); 3270f310cd6SCorey Minyard IPMIKCS *ik = iic->get_backend_data(ii); 3280f310cd6SCorey Minyard 3290f310cd6SCorey Minyard ik->irqs_enabled = val; 3300f310cd6SCorey Minyard } 3310f310cd6SCorey Minyard 332*79d29a9dSCorey Minyard /* min_size must be a power of 2. */ 333*79d29a9dSCorey Minyard static void ipmi_kcs_init(IPMIInterface *ii, unsigned int min_size, 334*79d29a9dSCorey Minyard Error **errp) 3350f310cd6SCorey Minyard { 3360f310cd6SCorey Minyard IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii); 3370f310cd6SCorey Minyard IPMIKCS *ik = iic->get_backend_data(ii); 3380f310cd6SCorey Minyard 339*79d29a9dSCorey Minyard if (min_size == 0) { 340*79d29a9dSCorey Minyard min_size = 2; 341*79d29a9dSCorey Minyard } 342*79d29a9dSCorey Minyard ik->size_mask = min_size - 1; 3430f310cd6SCorey Minyard ik->io_length = 2; 344*79d29a9dSCorey Minyard memory_region_init_io(&ik->io, NULL, &ipmi_kcs_io_ops, ii, "ipmi-kcs", 345*79d29a9dSCorey Minyard min_size); 3460f310cd6SCorey Minyard } 3470f310cd6SCorey Minyard 3480f310cd6SCorey Minyard int ipmi_kcs_vmstate_post_load(void *opaque, int version) 3490f310cd6SCorey Minyard { 3500f310cd6SCorey Minyard IPMIKCS *ik = opaque; 3510f310cd6SCorey Minyard 3520f310cd6SCorey Minyard /* Make sure all the values are sane. */ 3530f310cd6SCorey Minyard if (ik->outpos >= MAX_IPMI_MSG_SIZE || ik->outlen >= MAX_IPMI_MSG_SIZE || 3540f310cd6SCorey Minyard ik->outpos >= ik->outlen) { 3550f310cd6SCorey Minyard qemu_log_mask(LOG_GUEST_ERROR, 3560f310cd6SCorey Minyard "ipmi:kcs: vmstate transfer received bad out values: %d %d\n", 3570f310cd6SCorey Minyard ik->outpos, ik->outlen); 3580f310cd6SCorey Minyard ik->outpos = 0; 3590f310cd6SCorey Minyard ik->outlen = 0; 3600f310cd6SCorey Minyard } 3610f310cd6SCorey Minyard 3620f310cd6SCorey Minyard if (ik->inlen >= MAX_IPMI_MSG_SIZE) { 3630f310cd6SCorey Minyard qemu_log_mask(LOG_GUEST_ERROR, 3640f310cd6SCorey Minyard "ipmi:kcs: vmstate transfer received bad in value: %d\n", 3650f310cd6SCorey Minyard ik->inlen); 3660f310cd6SCorey Minyard ik->inlen = 0; 3670f310cd6SCorey Minyard } 3680f310cd6SCorey Minyard 3690f310cd6SCorey Minyard return 0; 3700f310cd6SCorey Minyard } 3710f310cd6SCorey Minyard 3720f310cd6SCorey Minyard static bool vmstate_kcs_before_version2(void *opaque, int version) 3730f310cd6SCorey Minyard { 3740f310cd6SCorey Minyard return version <= 1; 3750f310cd6SCorey Minyard } 3760f310cd6SCorey Minyard 3770f310cd6SCorey Minyard const VMStateDescription vmstate_IPMIKCS = { 3780f310cd6SCorey Minyard .name = TYPE_IPMI_INTERFACE_PREFIX "kcs", 3790f310cd6SCorey Minyard .version_id = 2, 3800f310cd6SCorey Minyard .minimum_version_id = 1, 3810f310cd6SCorey Minyard .post_load = ipmi_kcs_vmstate_post_load, 3820f310cd6SCorey Minyard .fields = (VMStateField[]) { 3830f310cd6SCorey Minyard VMSTATE_BOOL(obf_irq_set, IPMIKCS), 3840f310cd6SCorey Minyard VMSTATE_BOOL(atn_irq_set, IPMIKCS), 3850f310cd6SCorey Minyard VMSTATE_UNUSED_TEST(vmstate_kcs_before_version2, 1), /* Was use_irq */ 3860f310cd6SCorey Minyard VMSTATE_BOOL(irqs_enabled, IPMIKCS), 3870f310cd6SCorey Minyard VMSTATE_UINT32(outpos, IPMIKCS), 3880f310cd6SCorey Minyard VMSTATE_UINT32_V(outlen, IPMIKCS, 2), 3890f310cd6SCorey Minyard VMSTATE_UINT8_ARRAY(outmsg, IPMIKCS, MAX_IPMI_MSG_SIZE), 3900f310cd6SCorey Minyard VMSTATE_UINT32_V(inlen, IPMIKCS, 2), 3910f310cd6SCorey Minyard VMSTATE_UINT8_ARRAY(inmsg, IPMIKCS, MAX_IPMI_MSG_SIZE), 3920f310cd6SCorey Minyard VMSTATE_BOOL(write_end, IPMIKCS), 3930f310cd6SCorey Minyard VMSTATE_UINT8(status_reg, IPMIKCS), 3940f310cd6SCorey Minyard VMSTATE_UINT8(data_out_reg, IPMIKCS), 3950f310cd6SCorey Minyard VMSTATE_INT16(data_in_reg, IPMIKCS), 3960f310cd6SCorey Minyard VMSTATE_INT16(cmd_reg, IPMIKCS), 3970f310cd6SCorey Minyard VMSTATE_UINT8(waiting_rsp, IPMIKCS), 3980f310cd6SCorey Minyard VMSTATE_END_OF_LIST() 3990f310cd6SCorey Minyard } 4000f310cd6SCorey Minyard }; 4010f310cd6SCorey Minyard 4020f310cd6SCorey Minyard void ipmi_kcs_get_fwinfo(IPMIKCS *ik, IPMIFwInfo *info) 4030f310cd6SCorey Minyard { 4040f310cd6SCorey Minyard info->interface_name = "kcs"; 4050f310cd6SCorey Minyard info->interface_type = IPMI_SMBIOS_KCS; 4060f310cd6SCorey Minyard info->ipmi_spec_major_revision = 2; 4070f310cd6SCorey Minyard info->ipmi_spec_minor_revision = 0; 4080f310cd6SCorey Minyard info->base_address = ik->io_base; 4090f310cd6SCorey Minyard info->i2c_slave_address = ik->bmc->slave_addr; 4100f310cd6SCorey Minyard info->register_length = ik->io_length; 4110f310cd6SCorey Minyard info->register_spacing = 1; 4120f310cd6SCorey Minyard info->memspace = IPMI_MEMSPACE_IO; 4130f310cd6SCorey Minyard info->irq_type = IPMI_LEVEL_IRQ; 4140f310cd6SCorey Minyard } 4150f310cd6SCorey Minyard 4160f310cd6SCorey Minyard void ipmi_kcs_class_init(IPMIInterfaceClass *iic) 4170f310cd6SCorey Minyard { 4180f310cd6SCorey Minyard iic->init = ipmi_kcs_init; 4190f310cd6SCorey Minyard iic->set_atn = ipmi_kcs_set_atn; 4200f310cd6SCorey Minyard iic->handle_rsp = ipmi_kcs_handle_rsp; 4210f310cd6SCorey Minyard iic->handle_if_event = ipmi_kcs_handle_event; 4220f310cd6SCorey Minyard iic->set_irq_enable = ipmi_kcs_set_irq_enable; 4230f310cd6SCorey Minyard } 424