10719029cSCorey Minyard /* 20719029cSCorey Minyard * QEMU ISA IPMI KCS emulation 30719029cSCorey Minyard * 40719029cSCorey Minyard * Copyright (c) 2015 Corey Minyard, MontaVista Software, LLC 50719029cSCorey Minyard * 60719029cSCorey Minyard * Permission is hereby granted, free of charge, to any person obtaining a copy 70719029cSCorey Minyard * of this software and associated documentation files (the "Software"), to deal 80719029cSCorey Minyard * in the Software without restriction, including without limitation the rights 90719029cSCorey Minyard * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 100719029cSCorey Minyard * copies of the Software, and to permit persons to whom the Software is 110719029cSCorey Minyard * furnished to do so, subject to the following conditions: 120719029cSCorey Minyard * 130719029cSCorey Minyard * The above copyright notice and this permission notice shall be included in 140719029cSCorey Minyard * all copies or substantial portions of the Software. 150719029cSCorey Minyard * 160719029cSCorey Minyard * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 170719029cSCorey Minyard * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 180719029cSCorey Minyard * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 190719029cSCorey Minyard * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 200719029cSCorey Minyard * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 210719029cSCorey Minyard * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 220719029cSCorey Minyard * THE SOFTWARE. 230719029cSCorey Minyard */ 240b8fa32fSMarkus Armbruster 250430891cSPeter Maydell #include "qemu/osdep.h" 267e57b82eSCorey Minyard #include "qemu/log.h" 270b8fa32fSMarkus Armbruster #include "qemu/module.h" 28da34e65cSMarkus Armbruster #include "qapi/error.h" 290719029cSCorey Minyard #include "hw/ipmi/ipmi.h" 3064552b6bSMarkus Armbruster #include "hw/irq.h" 310719029cSCorey Minyard #include "hw/isa/isa.h" 32*a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h" 33d6454270SMarkus Armbruster #include "migration/vmstate.h" 340719029cSCorey Minyard 350719029cSCorey Minyard #define IPMI_KCS_OBF_BIT 0 360719029cSCorey Minyard #define IPMI_KCS_IBF_BIT 1 370719029cSCorey Minyard #define IPMI_KCS_SMS_ATN_BIT 2 380719029cSCorey Minyard #define IPMI_KCS_CD_BIT 3 390719029cSCorey Minyard 400719029cSCorey Minyard #define IPMI_KCS_OBF_MASK (1 << IPMI_KCS_OBF_BIT) 410719029cSCorey Minyard #define IPMI_KCS_GET_OBF(d) (((d) >> IPMI_KCS_OBF_BIT) & 0x1) 420719029cSCorey Minyard #define IPMI_KCS_SET_OBF(d, v) (d) = (((d) & ~IPMI_KCS_OBF_MASK) | \ 430719029cSCorey Minyard (((v) & 1) << IPMI_KCS_OBF_BIT)) 440719029cSCorey Minyard #define IPMI_KCS_IBF_MASK (1 << IPMI_KCS_IBF_BIT) 450719029cSCorey Minyard #define IPMI_KCS_GET_IBF(d) (((d) >> IPMI_KCS_IBF_BIT) & 0x1) 460719029cSCorey Minyard #define IPMI_KCS_SET_IBF(d, v) (d) = (((d) & ~IPMI_KCS_IBF_MASK) | \ 470719029cSCorey Minyard (((v) & 1) << IPMI_KCS_IBF_BIT)) 480719029cSCorey Minyard #define IPMI_KCS_SMS_ATN_MASK (1 << IPMI_KCS_SMS_ATN_BIT) 490719029cSCorey Minyard #define IPMI_KCS_GET_SMS_ATN(d) (((d) >> IPMI_KCS_SMS_ATN_BIT) & 0x1) 500719029cSCorey Minyard #define IPMI_KCS_SET_SMS_ATN(d, v) (d) = (((d) & ~IPMI_KCS_SMS_ATN_MASK) | \ 510719029cSCorey Minyard (((v) & 1) << IPMI_KCS_SMS_ATN_BIT)) 520719029cSCorey Minyard #define IPMI_KCS_CD_MASK (1 << IPMI_KCS_CD_BIT) 530719029cSCorey Minyard #define IPMI_KCS_GET_CD(d) (((d) >> IPMI_KCS_CD_BIT) & 0x1) 540719029cSCorey Minyard #define IPMI_KCS_SET_CD(d, v) (d) = (((d) & ~IPMI_KCS_CD_MASK) | \ 550719029cSCorey Minyard (((v) & 1) << IPMI_KCS_CD_BIT)) 560719029cSCorey Minyard 570719029cSCorey Minyard #define IPMI_KCS_IDLE_STATE 0 580719029cSCorey Minyard #define IPMI_KCS_READ_STATE 1 590719029cSCorey Minyard #define IPMI_KCS_WRITE_STATE 2 600719029cSCorey Minyard #define IPMI_KCS_ERROR_STATE 3 610719029cSCorey Minyard 620719029cSCorey Minyard #define IPMI_KCS_GET_STATE(d) (((d) >> 6) & 0x3) 630719029cSCorey Minyard #define IPMI_KCS_SET_STATE(d, v) ((d) = ((d) & ~0xc0) | (((v) & 0x3) << 6)) 640719029cSCorey Minyard 650719029cSCorey Minyard #define IPMI_KCS_ABORT_STATUS_CMD 0x60 660719029cSCorey Minyard #define IPMI_KCS_WRITE_START_CMD 0x61 670719029cSCorey Minyard #define IPMI_KCS_WRITE_END_CMD 0x62 680719029cSCorey Minyard #define IPMI_KCS_READ_CMD 0x68 690719029cSCorey Minyard 700719029cSCorey Minyard #define IPMI_KCS_STATUS_NO_ERR 0x00 710719029cSCorey Minyard #define IPMI_KCS_STATUS_ABORTED_ERR 0x01 720719029cSCorey Minyard #define IPMI_KCS_STATUS_BAD_CC_ERR 0x02 730719029cSCorey Minyard #define IPMI_KCS_STATUS_LENGTH_ERR 0x06 740719029cSCorey Minyard 750719029cSCorey Minyard typedef struct IPMIKCS { 760719029cSCorey Minyard IPMIBmc *bmc; 770719029cSCorey Minyard 780719029cSCorey Minyard bool do_wake; 790719029cSCorey Minyard 800719029cSCorey Minyard qemu_irq irq; 810719029cSCorey Minyard 820719029cSCorey Minyard uint32_t io_base; 830719029cSCorey Minyard unsigned long io_length; 840719029cSCorey Minyard MemoryRegion io; 850719029cSCorey Minyard 860719029cSCorey Minyard bool obf_irq_set; 870719029cSCorey Minyard bool atn_irq_set; 880719029cSCorey Minyard bool use_irq; 890719029cSCorey Minyard bool irqs_enabled; 900719029cSCorey Minyard 910719029cSCorey Minyard uint8_t outmsg[MAX_IPMI_MSG_SIZE]; 920719029cSCorey Minyard uint32_t outpos; 930719029cSCorey Minyard uint32_t outlen; 940719029cSCorey Minyard 950719029cSCorey Minyard uint8_t inmsg[MAX_IPMI_MSG_SIZE]; 960719029cSCorey Minyard uint32_t inlen; 970719029cSCorey Minyard bool write_end; 980719029cSCorey Minyard 990719029cSCorey Minyard uint8_t status_reg; 1000719029cSCorey Minyard uint8_t data_out_reg; 1010719029cSCorey Minyard 1020719029cSCorey Minyard int16_t data_in_reg; /* -1 means not written */ 1030719029cSCorey Minyard int16_t cmd_reg; 1040719029cSCorey Minyard 1050719029cSCorey Minyard /* 1060719029cSCorey Minyard * This is a response number that we send with the command to make 1070719029cSCorey Minyard * sure that the response matches the command. 1080719029cSCorey Minyard */ 1090719029cSCorey Minyard uint8_t waiting_rsp; 1100719029cSCorey Minyard } IPMIKCS; 1110719029cSCorey Minyard 1120719029cSCorey Minyard #define SET_OBF() \ 1130719029cSCorey Minyard do { \ 1140719029cSCorey Minyard IPMI_KCS_SET_OBF(ik->status_reg, 1); \ 1150719029cSCorey Minyard if (ik->use_irq && ik->irqs_enabled && !ik->obf_irq_set) { \ 1160719029cSCorey Minyard ik->obf_irq_set = 1; \ 1170719029cSCorey Minyard if (!ik->atn_irq_set) { \ 1180719029cSCorey Minyard qemu_irq_raise(ik->irq); \ 1190719029cSCorey Minyard } \ 1200719029cSCorey Minyard } \ 1210719029cSCorey Minyard } while (0) 1220719029cSCorey Minyard 1230719029cSCorey Minyard static void ipmi_kcs_signal(IPMIKCS *ik, IPMIInterface *ii) 1240719029cSCorey Minyard { 1250719029cSCorey Minyard IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii); 1260719029cSCorey Minyard 1270719029cSCorey Minyard ik->do_wake = 1; 1280719029cSCorey Minyard while (ik->do_wake) { 1290719029cSCorey Minyard ik->do_wake = 0; 1300719029cSCorey Minyard iic->handle_if_event(ii); 1310719029cSCorey Minyard } 1320719029cSCorey Minyard } 1330719029cSCorey Minyard 1340719029cSCorey Minyard static void ipmi_kcs_handle_event(IPMIInterface *ii) 1350719029cSCorey Minyard { 1360719029cSCorey Minyard IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii); 1370719029cSCorey Minyard IPMIKCS *ik = iic->get_backend_data(ii); 1380719029cSCorey Minyard 1390719029cSCorey Minyard if (ik->cmd_reg == IPMI_KCS_ABORT_STATUS_CMD) { 1400719029cSCorey Minyard if (IPMI_KCS_GET_STATE(ik->status_reg) != IPMI_KCS_ERROR_STATE) { 1410719029cSCorey Minyard ik->waiting_rsp++; /* Invalidate the message */ 1420719029cSCorey Minyard ik->outmsg[0] = IPMI_KCS_STATUS_ABORTED_ERR; 1430719029cSCorey Minyard ik->outlen = 1; 1440719029cSCorey Minyard ik->outpos = 0; 1450719029cSCorey Minyard IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_ERROR_STATE); 1460719029cSCorey Minyard SET_OBF(); 1470719029cSCorey Minyard } 1480719029cSCorey Minyard goto out; 1490719029cSCorey Minyard } 1500719029cSCorey Minyard 1510719029cSCorey Minyard switch (IPMI_KCS_GET_STATE(ik->status_reg)) { 1520719029cSCorey Minyard case IPMI_KCS_IDLE_STATE: 1530719029cSCorey Minyard if (ik->cmd_reg == IPMI_KCS_WRITE_START_CMD) { 1540719029cSCorey Minyard IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_WRITE_STATE); 1550719029cSCorey Minyard ik->cmd_reg = -1; 1560719029cSCorey Minyard ik->write_end = 0; 1570719029cSCorey Minyard ik->inlen = 0; 1580719029cSCorey Minyard SET_OBF(); 1590719029cSCorey Minyard } 1600719029cSCorey Minyard break; 1610719029cSCorey Minyard 1620719029cSCorey Minyard case IPMI_KCS_READ_STATE: 1630719029cSCorey Minyard handle_read: 1640719029cSCorey Minyard if (ik->outpos >= ik->outlen) { 1650719029cSCorey Minyard IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_IDLE_STATE); 1660719029cSCorey Minyard SET_OBF(); 1670719029cSCorey Minyard } else if (ik->data_in_reg == IPMI_KCS_READ_CMD) { 1680719029cSCorey Minyard ik->data_out_reg = ik->outmsg[ik->outpos]; 1690719029cSCorey Minyard ik->outpos++; 1700719029cSCorey Minyard SET_OBF(); 1710719029cSCorey Minyard } else { 1720719029cSCorey Minyard ik->outmsg[0] = IPMI_KCS_STATUS_BAD_CC_ERR; 1730719029cSCorey Minyard ik->outlen = 1; 1740719029cSCorey Minyard ik->outpos = 0; 1750719029cSCorey Minyard IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_ERROR_STATE); 1760719029cSCorey Minyard SET_OBF(); 1770719029cSCorey Minyard goto out; 1780719029cSCorey Minyard } 1790719029cSCorey Minyard break; 1800719029cSCorey Minyard 1810719029cSCorey Minyard case IPMI_KCS_WRITE_STATE: 1820719029cSCorey Minyard if (ik->data_in_reg != -1) { 1830719029cSCorey Minyard /* 1840719029cSCorey Minyard * Don't worry about input overrun here, that will be 1850719029cSCorey Minyard * handled in the BMC. 1860719029cSCorey Minyard */ 1870719029cSCorey Minyard if (ik->inlen < sizeof(ik->inmsg)) { 1880719029cSCorey Minyard ik->inmsg[ik->inlen] = ik->data_in_reg; 1890719029cSCorey Minyard } 1900719029cSCorey Minyard ik->inlen++; 1910719029cSCorey Minyard } 1920719029cSCorey Minyard if (ik->write_end) { 1930719029cSCorey Minyard IPMIBmcClass *bk = IPMI_BMC_GET_CLASS(ik->bmc); 1940719029cSCorey Minyard ik->outlen = 0; 1950719029cSCorey Minyard ik->write_end = 0; 1960719029cSCorey Minyard ik->outpos = 0; 1970719029cSCorey Minyard bk->handle_command(ik->bmc, ik->inmsg, ik->inlen, sizeof(ik->inmsg), 1980719029cSCorey Minyard ik->waiting_rsp); 1990719029cSCorey Minyard goto out_noibf; 2000719029cSCorey Minyard } else if (ik->cmd_reg == IPMI_KCS_WRITE_END_CMD) { 2010719029cSCorey Minyard ik->cmd_reg = -1; 2020719029cSCorey Minyard ik->write_end = 1; 2030719029cSCorey Minyard } 2040719029cSCorey Minyard SET_OBF(); 2050719029cSCorey Minyard break; 2060719029cSCorey Minyard 2070719029cSCorey Minyard case IPMI_KCS_ERROR_STATE: 2080719029cSCorey Minyard if (ik->data_in_reg != -1) { 2090719029cSCorey Minyard IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_READ_STATE); 2100719029cSCorey Minyard ik->data_in_reg = IPMI_KCS_READ_CMD; 2110719029cSCorey Minyard goto handle_read; 2120719029cSCorey Minyard } 2130719029cSCorey Minyard break; 2140719029cSCorey Minyard } 2150719029cSCorey Minyard 2160719029cSCorey Minyard if (ik->cmd_reg != -1) { 2170719029cSCorey Minyard /* Got an invalid command */ 2180719029cSCorey Minyard ik->outmsg[0] = IPMI_KCS_STATUS_BAD_CC_ERR; 2190719029cSCorey Minyard ik->outlen = 1; 2200719029cSCorey Minyard ik->outpos = 0; 2210719029cSCorey Minyard IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_ERROR_STATE); 2220719029cSCorey Minyard } 2230719029cSCorey Minyard 2240719029cSCorey Minyard out: 2250719029cSCorey Minyard ik->cmd_reg = -1; 2260719029cSCorey Minyard ik->data_in_reg = -1; 2270719029cSCorey Minyard IPMI_KCS_SET_IBF(ik->status_reg, 0); 2280719029cSCorey Minyard out_noibf: 2290719029cSCorey Minyard return; 2300719029cSCorey Minyard } 2310719029cSCorey Minyard 2320719029cSCorey Minyard static void ipmi_kcs_handle_rsp(IPMIInterface *ii, uint8_t msg_id, 2330719029cSCorey Minyard unsigned char *rsp, unsigned int rsp_len) 2340719029cSCorey Minyard { 2350719029cSCorey Minyard IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii); 2360719029cSCorey Minyard IPMIKCS *ik = iic->get_backend_data(ii); 2370719029cSCorey Minyard 2380719029cSCorey Minyard if (ik->waiting_rsp == msg_id) { 2390719029cSCorey Minyard ik->waiting_rsp++; 2400719029cSCorey Minyard if (rsp_len > sizeof(ik->outmsg)) { 2410719029cSCorey Minyard ik->outmsg[0] = rsp[0]; 2420719029cSCorey Minyard ik->outmsg[1] = rsp[1]; 2430719029cSCorey Minyard ik->outmsg[2] = IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES; 2440719029cSCorey Minyard ik->outlen = 3; 2450719029cSCorey Minyard } else { 2460719029cSCorey Minyard memcpy(ik->outmsg, rsp, rsp_len); 2470719029cSCorey Minyard ik->outlen = rsp_len; 2480719029cSCorey Minyard } 2490719029cSCorey Minyard IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_READ_STATE); 2500719029cSCorey Minyard ik->data_in_reg = IPMI_KCS_READ_CMD; 2510719029cSCorey Minyard ipmi_kcs_signal(ik, ii); 2520719029cSCorey Minyard } 2530719029cSCorey Minyard } 2540719029cSCorey Minyard 2550719029cSCorey Minyard 2560719029cSCorey Minyard static uint64_t ipmi_kcs_ioport_read(void *opaque, hwaddr addr, unsigned size) 2570719029cSCorey Minyard { 2580719029cSCorey Minyard IPMIInterface *ii = opaque; 2590719029cSCorey Minyard IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii); 2600719029cSCorey Minyard IPMIKCS *ik = iic->get_backend_data(ii); 2610719029cSCorey Minyard uint32_t ret; 2620719029cSCorey Minyard 2630719029cSCorey Minyard switch (addr & 1) { 2640719029cSCorey Minyard case 0: 2650719029cSCorey Minyard ret = ik->data_out_reg; 2660719029cSCorey Minyard IPMI_KCS_SET_OBF(ik->status_reg, 0); 2670719029cSCorey Minyard if (ik->obf_irq_set) { 2680719029cSCorey Minyard ik->obf_irq_set = 0; 2690719029cSCorey Minyard if (!ik->atn_irq_set) { 2700719029cSCorey Minyard qemu_irq_lower(ik->irq); 2710719029cSCorey Minyard } 2720719029cSCorey Minyard } 2730719029cSCorey Minyard break; 2740719029cSCorey Minyard case 1: 2750719029cSCorey Minyard ret = ik->status_reg; 2760719029cSCorey Minyard if (ik->atn_irq_set) { 2770719029cSCorey Minyard ik->atn_irq_set = 0; 2780719029cSCorey Minyard if (!ik->obf_irq_set) { 2790719029cSCorey Minyard qemu_irq_lower(ik->irq); 2800719029cSCorey Minyard } 2810719029cSCorey Minyard } 2820719029cSCorey Minyard break; 2830719029cSCorey Minyard } 2840719029cSCorey Minyard return ret; 2850719029cSCorey Minyard } 2860719029cSCorey Minyard 2870719029cSCorey Minyard static void ipmi_kcs_ioport_write(void *opaque, hwaddr addr, uint64_t val, 2880719029cSCorey Minyard unsigned size) 2890719029cSCorey Minyard { 2900719029cSCorey Minyard IPMIInterface *ii = opaque; 2910719029cSCorey Minyard IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii); 2920719029cSCorey Minyard IPMIKCS *ik = iic->get_backend_data(ii); 2930719029cSCorey Minyard 2940719029cSCorey Minyard if (IPMI_KCS_GET_IBF(ik->status_reg)) { 2950719029cSCorey Minyard return; 2960719029cSCorey Minyard } 2970719029cSCorey Minyard 2980719029cSCorey Minyard switch (addr & 1) { 2990719029cSCorey Minyard case 0: 3000719029cSCorey Minyard ik->data_in_reg = val; 3010719029cSCorey Minyard break; 3020719029cSCorey Minyard 3030719029cSCorey Minyard case 1: 3040719029cSCorey Minyard ik->cmd_reg = val; 3050719029cSCorey Minyard break; 3060719029cSCorey Minyard } 3070719029cSCorey Minyard IPMI_KCS_SET_IBF(ik->status_reg, 1); 3080719029cSCorey Minyard ipmi_kcs_signal(ik, ii); 3090719029cSCorey Minyard } 3100719029cSCorey Minyard 3110719029cSCorey Minyard const MemoryRegionOps ipmi_kcs_io_ops = { 3120719029cSCorey Minyard .read = ipmi_kcs_ioport_read, 3130719029cSCorey Minyard .write = ipmi_kcs_ioport_write, 3140719029cSCorey Minyard .impl = { 3150719029cSCorey Minyard .min_access_size = 1, 3160719029cSCorey Minyard .max_access_size = 1, 3170719029cSCorey Minyard }, 3180719029cSCorey Minyard .endianness = DEVICE_LITTLE_ENDIAN, 3190719029cSCorey Minyard }; 3200719029cSCorey Minyard 3210719029cSCorey Minyard static void ipmi_kcs_set_atn(IPMIInterface *ii, int val, int irq) 3220719029cSCorey Minyard { 3230719029cSCorey Minyard IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii); 3240719029cSCorey Minyard IPMIKCS *ik = iic->get_backend_data(ii); 3250719029cSCorey Minyard 3260719029cSCorey Minyard IPMI_KCS_SET_SMS_ATN(ik->status_reg, val); 3270719029cSCorey Minyard if (val) { 3280719029cSCorey Minyard if (irq && !ik->atn_irq_set && ik->use_irq && ik->irqs_enabled) { 3290719029cSCorey Minyard ik->atn_irq_set = 1; 3300719029cSCorey Minyard if (!ik->obf_irq_set) { 3310719029cSCorey Minyard qemu_irq_raise(ik->irq); 3320719029cSCorey Minyard } 3330719029cSCorey Minyard } 3340719029cSCorey Minyard } else { 3350719029cSCorey Minyard if (ik->atn_irq_set) { 3360719029cSCorey Minyard ik->atn_irq_set = 0; 3370719029cSCorey Minyard if (!ik->obf_irq_set) { 3380719029cSCorey Minyard qemu_irq_lower(ik->irq); 3390719029cSCorey Minyard } 3400719029cSCorey Minyard } 3410719029cSCorey Minyard } 3420719029cSCorey Minyard } 3430719029cSCorey Minyard 3440719029cSCorey Minyard static void ipmi_kcs_set_irq_enable(IPMIInterface *ii, int val) 3450719029cSCorey Minyard { 3460719029cSCorey Minyard IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii); 3470719029cSCorey Minyard IPMIKCS *ik = iic->get_backend_data(ii); 3480719029cSCorey Minyard 3490719029cSCorey Minyard ik->irqs_enabled = val; 3500719029cSCorey Minyard } 3510719029cSCorey Minyard 3520719029cSCorey Minyard static void ipmi_kcs_init(IPMIInterface *ii, Error **errp) 3530719029cSCorey Minyard { 3540719029cSCorey Minyard IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii); 3550719029cSCorey Minyard IPMIKCS *ik = iic->get_backend_data(ii); 3560719029cSCorey Minyard 3570719029cSCorey Minyard ik->io_length = 2; 3580719029cSCorey Minyard memory_region_init_io(&ik->io, NULL, &ipmi_kcs_io_ops, ii, "ipmi-kcs", 2); 3590719029cSCorey Minyard } 3600719029cSCorey Minyard 3610719029cSCorey Minyard #define TYPE_ISA_IPMI_KCS "isa-ipmi-kcs" 3620719029cSCorey Minyard #define ISA_IPMI_KCS(obj) OBJECT_CHECK(ISAIPMIKCSDevice, (obj), \ 3630719029cSCorey Minyard TYPE_ISA_IPMI_KCS) 3640719029cSCorey Minyard 3650719029cSCorey Minyard typedef struct ISAIPMIKCSDevice { 3660719029cSCorey Minyard ISADevice dev; 367f4014512SPeter Maydell int32_t isairq; 3680719029cSCorey Minyard IPMIKCS kcs; 36915139b8eSCorey Minyard uint32_t uuid; 3700719029cSCorey Minyard } ISAIPMIKCSDevice; 3710719029cSCorey Minyard 37215139b8eSCorey Minyard static void ipmi_kcs_get_fwinfo(IPMIInterface *ii, IPMIFwInfo *info) 37315139b8eSCorey Minyard { 37415139b8eSCorey Minyard ISAIPMIKCSDevice *iik = ISA_IPMI_KCS(ii); 37515139b8eSCorey Minyard 37615139b8eSCorey Minyard info->interface_name = "kcs"; 37715139b8eSCorey Minyard info->interface_type = IPMI_SMBIOS_KCS; 37815139b8eSCorey Minyard info->ipmi_spec_major_revision = 2; 37915139b8eSCorey Minyard info->ipmi_spec_minor_revision = 0; 38015139b8eSCorey Minyard info->base_address = iik->kcs.io_base; 38115139b8eSCorey Minyard info->i2c_slave_address = iik->kcs.bmc->slave_addr; 38215139b8eSCorey Minyard info->register_length = iik->kcs.io_length; 38315139b8eSCorey Minyard info->register_spacing = 1; 38415139b8eSCorey Minyard info->memspace = IPMI_MEMSPACE_IO; 38515139b8eSCorey Minyard info->irq_type = IPMI_LEVEL_IRQ; 38615139b8eSCorey Minyard info->interrupt_number = iik->isairq; 38715139b8eSCorey Minyard info->uuid = iik->uuid; 38815139b8eSCorey Minyard } 38915139b8eSCorey Minyard 39015139b8eSCorey Minyard static void ipmi_kcs_class_init(IPMIInterfaceClass *iic) 39115139b8eSCorey Minyard { 39215139b8eSCorey Minyard iic->init = ipmi_kcs_init; 39315139b8eSCorey Minyard iic->set_atn = ipmi_kcs_set_atn; 39415139b8eSCorey Minyard iic->handle_rsp = ipmi_kcs_handle_rsp; 39515139b8eSCorey Minyard iic->handle_if_event = ipmi_kcs_handle_event; 39615139b8eSCorey Minyard iic->set_irq_enable = ipmi_kcs_set_irq_enable; 39715139b8eSCorey Minyard iic->get_fwinfo = ipmi_kcs_get_fwinfo; 39815139b8eSCorey Minyard } 39915139b8eSCorey Minyard 4000719029cSCorey Minyard static void ipmi_isa_realize(DeviceState *dev, Error **errp) 4010719029cSCorey Minyard { 4020719029cSCorey Minyard ISADevice *isadev = ISA_DEVICE(dev); 4030719029cSCorey Minyard ISAIPMIKCSDevice *iik = ISA_IPMI_KCS(dev); 4040719029cSCorey Minyard IPMIInterface *ii = IPMI_INTERFACE(dev); 4050719029cSCorey Minyard IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii); 4060719029cSCorey Minyard 4070719029cSCorey Minyard if (!iik->kcs.bmc) { 4080719029cSCorey Minyard error_setg(errp, "IPMI device requires a bmc attribute to be set"); 4090719029cSCorey Minyard return; 4100719029cSCorey Minyard } 4110719029cSCorey Minyard 41215139b8eSCorey Minyard iik->uuid = ipmi_next_uuid(); 41315139b8eSCorey Minyard 4140719029cSCorey Minyard iik->kcs.bmc->intf = ii; 4150719029cSCorey Minyard 4160719029cSCorey Minyard iic->init(ii, errp); 4170719029cSCorey Minyard if (*errp) 4180719029cSCorey Minyard return; 4190719029cSCorey Minyard 4200719029cSCorey Minyard if (iik->isairq > 0) { 4210719029cSCorey Minyard isa_init_irq(isadev, &iik->kcs.irq, iik->isairq); 4220719029cSCorey Minyard iik->kcs.use_irq = 1; 4230719029cSCorey Minyard } 4240719029cSCorey Minyard 4250719029cSCorey Minyard qdev_set_legacy_instance_id(dev, iik->kcs.io_base, iik->kcs.io_length); 4260719029cSCorey Minyard 4270719029cSCorey Minyard isa_register_ioport(isadev, &iik->kcs.io, iik->kcs.io_base); 4280719029cSCorey Minyard } 4290719029cSCorey Minyard 4307e57b82eSCorey Minyard static int ipmi_kcs_vmstate_post_load(void *opaque, int version) 4317e57b82eSCorey Minyard { 4327e57b82eSCorey Minyard IPMIKCS *ik = opaque; 4337e57b82eSCorey Minyard 4347e57b82eSCorey Minyard /* Make sure all the values are sane. */ 4357e57b82eSCorey Minyard if (ik->outpos >= MAX_IPMI_MSG_SIZE || ik->outlen >= MAX_IPMI_MSG_SIZE || 4367e57b82eSCorey Minyard ik->outpos >= ik->outlen) { 4377e57b82eSCorey Minyard qemu_log_mask(LOG_GUEST_ERROR, 4387e57b82eSCorey Minyard "ipmi:kcs: vmstate transfer received bad out values: %d %d\n", 4397e57b82eSCorey Minyard ik->outpos, ik->outlen); 4407e57b82eSCorey Minyard ik->outpos = 0; 4417e57b82eSCorey Minyard ik->outlen = 0; 4427e57b82eSCorey Minyard } 4437e57b82eSCorey Minyard 4447e57b82eSCorey Minyard if (ik->inlen >= MAX_IPMI_MSG_SIZE) { 4457e57b82eSCorey Minyard qemu_log_mask(LOG_GUEST_ERROR, 4467e57b82eSCorey Minyard "ipmi:kcs: vmstate transfer received bad in value: %d\n", 4477e57b82eSCorey Minyard ik->inlen); 4487e57b82eSCorey Minyard ik->inlen = 0; 4497e57b82eSCorey Minyard } 4507e57b82eSCorey Minyard 4517e57b82eSCorey Minyard return 0; 4527e57b82eSCorey Minyard } 4537e57b82eSCorey Minyard 4547e57b82eSCorey Minyard static bool vmstate_kcs_before_version2(void *opaque, int version) 4557e57b82eSCorey Minyard { 4567e57b82eSCorey Minyard return version <= 1; 4577e57b82eSCorey Minyard } 4587e57b82eSCorey Minyard 4597e57b82eSCorey Minyard static const VMStateDescription vmstate_IPMIKCS = { 4607e57b82eSCorey Minyard .name = TYPE_IPMI_INTERFACE_PREFIX "kcs", 4617e57b82eSCorey Minyard .version_id = 2, 4627e57b82eSCorey Minyard .minimum_version_id = 1, 4637e57b82eSCorey Minyard .post_load = ipmi_kcs_vmstate_post_load, 4647e57b82eSCorey Minyard .fields = (VMStateField[]) { 4657e57b82eSCorey Minyard VMSTATE_BOOL(obf_irq_set, IPMIKCS), 4667e57b82eSCorey Minyard VMSTATE_BOOL(atn_irq_set, IPMIKCS), 4677e57b82eSCorey Minyard VMSTATE_UNUSED_TEST(vmstate_kcs_before_version2, 1), /* Was use_irq */ 4687e57b82eSCorey Minyard VMSTATE_BOOL(irqs_enabled, IPMIKCS), 4697e57b82eSCorey Minyard VMSTATE_UINT32(outpos, IPMIKCS), 4707e57b82eSCorey Minyard VMSTATE_UINT32_V(outlen, IPMIKCS, 2), 4717e57b82eSCorey Minyard VMSTATE_UINT8_ARRAY(outmsg, IPMIKCS, MAX_IPMI_MSG_SIZE), 4727e57b82eSCorey Minyard VMSTATE_UINT32_V(inlen, IPMIKCS, 2), 4737e57b82eSCorey Minyard VMSTATE_UINT8_ARRAY(inmsg, IPMIKCS, MAX_IPMI_MSG_SIZE), 4747e57b82eSCorey Minyard VMSTATE_BOOL(write_end, IPMIKCS), 4757e57b82eSCorey Minyard VMSTATE_UINT8(status_reg, IPMIKCS), 4767e57b82eSCorey Minyard VMSTATE_UINT8(data_out_reg, IPMIKCS), 4777e57b82eSCorey Minyard VMSTATE_INT16(data_in_reg, IPMIKCS), 4787e57b82eSCorey Minyard VMSTATE_INT16(cmd_reg, IPMIKCS), 4797e57b82eSCorey Minyard VMSTATE_UINT8(waiting_rsp, IPMIKCS), 4807e57b82eSCorey Minyard VMSTATE_END_OF_LIST() 4817e57b82eSCorey Minyard } 4827e57b82eSCorey Minyard }; 4837e57b82eSCorey Minyard 4847e57b82eSCorey Minyard static const VMStateDescription vmstate_ISAIPMIKCSDevice = { 485bd66bcfcSCorey Minyard .name = TYPE_IPMI_INTERFACE, 4867e57b82eSCorey Minyard .version_id = 2, 487bd66bcfcSCorey Minyard .minimum_version_id = 1, 488bd66bcfcSCorey Minyard .fields = (VMStateField[]) { 4897e57b82eSCorey Minyard VMSTATE_VSTRUCT_TEST(kcs, ISAIPMIKCSDevice, vmstate_kcs_before_version2, 4907e57b82eSCorey Minyard 0, vmstate_IPMIKCS, IPMIKCS, 1), 4917e57b82eSCorey Minyard VMSTATE_VSTRUCT_V(kcs, ISAIPMIKCSDevice, 2, vmstate_IPMIKCS, 4927e57b82eSCorey Minyard IPMIKCS, 2), 493bd66bcfcSCorey Minyard VMSTATE_END_OF_LIST() 494bd66bcfcSCorey Minyard } 495bd66bcfcSCorey Minyard }; 496bd66bcfcSCorey Minyard 4970719029cSCorey Minyard static void isa_ipmi_kcs_init(Object *obj) 4980719029cSCorey Minyard { 4990719029cSCorey Minyard ISAIPMIKCSDevice *iik = ISA_IPMI_KCS(obj); 5000719029cSCorey Minyard 5010719029cSCorey Minyard ipmi_bmc_find_and_link(obj, (Object **) &iik->kcs.bmc); 502bd66bcfcSCorey Minyard 5037e57b82eSCorey Minyard /* 5047e57b82eSCorey Minyard * Version 1 had an incorrect name, it clashed with the BT 5057e57b82eSCorey Minyard * IPMI device, so receive it, but transmit a different 5067e57b82eSCorey Minyard * version. 5077e57b82eSCorey Minyard */ 508bd66bcfcSCorey Minyard vmstate_register(NULL, 0, &vmstate_ISAIPMIKCSDevice, iik); 5090719029cSCorey Minyard } 5100719029cSCorey Minyard 5110719029cSCorey Minyard static void *isa_ipmi_kcs_get_backend_data(IPMIInterface *ii) 5120719029cSCorey Minyard { 5130719029cSCorey Minyard ISAIPMIKCSDevice *iik = ISA_IPMI_KCS(ii); 5140719029cSCorey Minyard 5150719029cSCorey Minyard return &iik->kcs; 5160719029cSCorey Minyard } 5170719029cSCorey Minyard 5180719029cSCorey Minyard static Property ipmi_isa_properties[] = { 5190719029cSCorey Minyard DEFINE_PROP_UINT32("ioport", ISAIPMIKCSDevice, kcs.io_base, 0xca2), 5200719029cSCorey Minyard DEFINE_PROP_INT32("irq", ISAIPMIKCSDevice, isairq, 5), 5210719029cSCorey Minyard DEFINE_PROP_END_OF_LIST(), 5220719029cSCorey Minyard }; 5230719029cSCorey Minyard 5240719029cSCorey Minyard static void isa_ipmi_kcs_class_init(ObjectClass *oc, void *data) 5250719029cSCorey Minyard { 5260719029cSCorey Minyard DeviceClass *dc = DEVICE_CLASS(oc); 5270719029cSCorey Minyard IPMIInterfaceClass *iic = IPMI_INTERFACE_CLASS(oc); 5280719029cSCorey Minyard 5290719029cSCorey Minyard dc->realize = ipmi_isa_realize; 5300719029cSCorey Minyard dc->props = ipmi_isa_properties; 5310719029cSCorey Minyard 5320719029cSCorey Minyard iic->get_backend_data = isa_ipmi_kcs_get_backend_data; 5330719029cSCorey Minyard ipmi_kcs_class_init(iic); 5340719029cSCorey Minyard } 5350719029cSCorey Minyard 5360719029cSCorey Minyard static const TypeInfo isa_ipmi_kcs_info = { 5370719029cSCorey Minyard .name = TYPE_ISA_IPMI_KCS, 5380719029cSCorey Minyard .parent = TYPE_ISA_DEVICE, 5390719029cSCorey Minyard .instance_size = sizeof(ISAIPMIKCSDevice), 5400719029cSCorey Minyard .instance_init = isa_ipmi_kcs_init, 5410719029cSCorey Minyard .class_init = isa_ipmi_kcs_class_init, 5420719029cSCorey Minyard .interfaces = (InterfaceInfo[]) { 5430719029cSCorey Minyard { TYPE_IPMI_INTERFACE }, 5440719029cSCorey Minyard { } 5450719029cSCorey Minyard } 5460719029cSCorey Minyard }; 5470719029cSCorey Minyard 5480719029cSCorey Minyard static void ipmi_register_types(void) 5490719029cSCorey Minyard { 5500719029cSCorey Minyard type_register_static(&isa_ipmi_kcs_info); 5510719029cSCorey Minyard } 5520719029cSCorey Minyard 5530719029cSCorey Minyard type_init(ipmi_register_types) 554