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