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