qemu/hw/ipmi/isa_ipmi_bt.c
<<
>>
Prefs
   1/*
   2 * QEMU ISA IPMI BT 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
  25#include "qemu/osdep.h"
  26#include "qemu/log.h"
  27#include "qemu/module.h"
  28#include "qapi/error.h"
  29#include "hw/hw.h"
  30#include "hw/ipmi/ipmi.h"
  31#include "hw/isa/isa.h"
  32
  33/* Control register */
  34#define IPMI_BT_CLR_WR_BIT         0
  35#define IPMI_BT_CLR_RD_BIT         1
  36#define IPMI_BT_H2B_ATN_BIT        2
  37#define IPMI_BT_B2H_ATN_BIT        3
  38#define IPMI_BT_SMS_ATN_BIT        4
  39#define IPMI_BT_HBUSY_BIT          6
  40#define IPMI_BT_BBUSY_BIT          7
  41
  42#define IPMI_BT_GET_CLR_WR(d)      (((d) >> IPMI_BT_CLR_WR_BIT) & 0x1)
  43
  44#define IPMI_BT_GET_CLR_RD(d)      (((d) >> IPMI_BT_CLR_RD_BIT) & 0x1)
  45
  46#define IPMI_BT_GET_H2B_ATN(d)     (((d) >> IPMI_BT_H2B_ATN_BIT) & 0x1)
  47
  48#define IPMI_BT_B2H_ATN_MASK       (1 << IPMI_BT_B2H_ATN_BIT)
  49#define IPMI_BT_GET_B2H_ATN(d)     (((d) >> IPMI_BT_B2H_ATN_BIT) & 0x1)
  50#define IPMI_BT_SET_B2H_ATN(d, v)  ((d) = (((d) & ~IPMI_BT_B2H_ATN_MASK) | \
  51                                        (!!(v) << IPMI_BT_B2H_ATN_BIT)))
  52
  53#define IPMI_BT_SMS_ATN_MASK       (1 << IPMI_BT_SMS_ATN_BIT)
  54#define IPMI_BT_GET_SMS_ATN(d)     (((d) >> IPMI_BT_SMS_ATN_BIT) & 0x1)
  55#define IPMI_BT_SET_SMS_ATN(d, v)  ((d) = (((d) & ~IPMI_BT_SMS_ATN_MASK) | \
  56                                        (!!(v) << IPMI_BT_SMS_ATN_BIT)))
  57
  58#define IPMI_BT_HBUSY_MASK         (1 << IPMI_BT_HBUSY_BIT)
  59#define IPMI_BT_GET_HBUSY(d)       (((d) >> IPMI_BT_HBUSY_BIT) & 0x1)
  60#define IPMI_BT_SET_HBUSY(d, v)    ((d) = (((d) & ~IPMI_BT_HBUSY_MASK) | \
  61                                       (!!(v) << IPMI_BT_HBUSY_BIT)))
  62
  63#define IPMI_BT_BBUSY_MASK         (1 << IPMI_BT_BBUSY_BIT)
  64#define IPMI_BT_SET_BBUSY(d, v)    ((d) = (((d) & ~IPMI_BT_BBUSY_MASK) | \
  65                                       (!!(v) << IPMI_BT_BBUSY_BIT)))
  66
  67
  68/* Mask register */
  69#define IPMI_BT_B2H_IRQ_EN_BIT     0
  70#define IPMI_BT_B2H_IRQ_BIT        1
  71
  72#define IPMI_BT_B2H_IRQ_EN_MASK      (1 << IPMI_BT_B2H_IRQ_EN_BIT)
  73#define IPMI_BT_GET_B2H_IRQ_EN(d)    (((d) >> IPMI_BT_B2H_IRQ_EN_BIT) & 0x1)
  74#define IPMI_BT_SET_B2H_IRQ_EN(d, v) ((d) = (((d) & ~IPMI_BT_B2H_IRQ_EN_MASK) |\
  75                                        (!!(v) << IPMI_BT_B2H_IRQ_EN_BIT)))
  76
  77#define IPMI_BT_B2H_IRQ_MASK         (1 << IPMI_BT_B2H_IRQ_BIT)
  78#define IPMI_BT_GET_B2H_IRQ(d)       (((d) >> IPMI_BT_B2H_IRQ_BIT) & 0x1)
  79#define IPMI_BT_SET_B2H_IRQ(d, v)    ((d) = (((d) & ~IPMI_BT_B2H_IRQ_MASK) | \
  80                                        (!!(v) << IPMI_BT_B2H_IRQ_BIT)))
  81
  82typedef struct IPMIBT {
  83    IPMIBmc *bmc;
  84
  85    bool do_wake;
  86
  87    qemu_irq irq;
  88
  89    uint32_t io_base;
  90    unsigned long io_length;
  91    MemoryRegion io;
  92
  93    bool obf_irq_set;
  94    bool atn_irq_set;
  95    bool use_irq;
  96    bool irqs_enabled;
  97
  98    uint8_t outmsg[MAX_IPMI_MSG_SIZE];
  99    uint32_t outpos;
 100    uint32_t outlen;
 101
 102    uint8_t inmsg[MAX_IPMI_MSG_SIZE];
 103    uint32_t inlen;
 104
 105    uint8_t control_reg;
 106    uint8_t mask_reg;
 107
 108    /*
 109     * This is a response number that we send with the command to make
 110     * sure that the response matches the command.
 111     */
 112    uint8_t waiting_rsp;
 113    uint8_t waiting_seq;
 114} IPMIBT;
 115
 116#define IPMI_CMD_GET_BT_INTF_CAP        0x36
 117
 118static void ipmi_bt_handle_event(IPMIInterface *ii)
 119{
 120    IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
 121    IPMIBT *ib = iic->get_backend_data(ii);
 122
 123    if (ib->inlen < 4) {
 124        goto out;
 125    }
 126    /* Note that overruns are handled by handle_command */
 127    if (ib->inmsg[0] != (ib->inlen - 1)) {
 128        /* Length mismatch, just ignore. */
 129        IPMI_BT_SET_BBUSY(ib->control_reg, 1);
 130        ib->inlen = 0;
 131        goto out;
 132    }
 133    if ((ib->inmsg[1] == (IPMI_NETFN_APP << 2)) &&
 134                        (ib->inmsg[3] == IPMI_CMD_GET_BT_INTF_CAP)) {
 135        /* We handle this one ourselves. */
 136        ib->outmsg[0] = 9;
 137        ib->outmsg[1] = ib->inmsg[1] | 0x04;
 138        ib->outmsg[2] = ib->inmsg[2];
 139        ib->outmsg[3] = ib->inmsg[3];
 140        ib->outmsg[4] = 0;
 141        ib->outmsg[5] = 1; /* Only support 1 outstanding request. */
 142        if (sizeof(ib->inmsg) > 0xff) { /* Input buffer size */
 143            ib->outmsg[6] = 0xff;
 144        } else {
 145            ib->outmsg[6] = (unsigned char) sizeof(ib->inmsg);
 146        }
 147        if (sizeof(ib->outmsg) > 0xff) { /* Output buffer size */
 148            ib->outmsg[7] = 0xff;
 149        } else {
 150            ib->outmsg[7] = (unsigned char) sizeof(ib->outmsg);
 151        }
 152        ib->outmsg[8] = 10; /* Max request to response time */
 153        ib->outmsg[9] = 0; /* Don't recommend retries */
 154        ib->outlen = 10;
 155        IPMI_BT_SET_BBUSY(ib->control_reg, 0);
 156        IPMI_BT_SET_B2H_ATN(ib->control_reg, 1);
 157        if (ib->use_irq && ib->irqs_enabled &&
 158                !IPMI_BT_GET_B2H_IRQ(ib->mask_reg) &&
 159                IPMI_BT_GET_B2H_IRQ_EN(ib->mask_reg)) {
 160            IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 1);
 161            qemu_irq_raise(ib->irq);
 162        }
 163        goto out;
 164    }
 165    ib->waiting_seq = ib->inmsg[2];
 166    ib->inmsg[2] = ib->inmsg[1];
 167    {
 168        IPMIBmcClass *bk = IPMI_BMC_GET_CLASS(ib->bmc);
 169        bk->handle_command(ib->bmc, ib->inmsg + 2, ib->inlen - 2,
 170                           sizeof(ib->inmsg), ib->waiting_rsp);
 171    }
 172 out:
 173    return;
 174}
 175
 176static void ipmi_bt_handle_rsp(IPMIInterface *ii, uint8_t msg_id,
 177                                unsigned char *rsp, unsigned int rsp_len)
 178{
 179    IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
 180    IPMIBT *ib = iic->get_backend_data(ii);
 181
 182    if (ib->waiting_rsp == msg_id) {
 183        ib->waiting_rsp++;
 184        if (rsp_len > (sizeof(ib->outmsg) - 2)) {
 185            ib->outmsg[0] = 4;
 186            ib->outmsg[1] = rsp[0];
 187            ib->outmsg[2] = ib->waiting_seq;
 188            ib->outmsg[3] = rsp[1];
 189            ib->outmsg[4] = IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES;
 190            ib->outlen = 5;
 191        } else {
 192            ib->outmsg[0] = rsp_len + 1;
 193            ib->outmsg[1] = rsp[0];
 194            ib->outmsg[2] = ib->waiting_seq;
 195            memcpy(ib->outmsg + 3, rsp + 1, rsp_len - 1);
 196            ib->outlen = rsp_len + 2;
 197        }
 198        IPMI_BT_SET_BBUSY(ib->control_reg, 0);
 199        IPMI_BT_SET_B2H_ATN(ib->control_reg, 1);
 200        if (ib->use_irq && ib->irqs_enabled &&
 201                !IPMI_BT_GET_B2H_IRQ(ib->mask_reg) &&
 202                IPMI_BT_GET_B2H_IRQ_EN(ib->mask_reg)) {
 203            IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 1);
 204            qemu_irq_raise(ib->irq);
 205        }
 206    }
 207}
 208
 209
 210static uint64_t ipmi_bt_ioport_read(void *opaque, hwaddr addr, unsigned size)
 211{
 212    IPMIInterface *ii = opaque;
 213    IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
 214    IPMIBT *ib = iic->get_backend_data(ii);
 215    uint32_t ret = 0xff;
 216
 217    switch (addr & 3) {
 218    case 0:
 219        ret = ib->control_reg;
 220        break;
 221    case 1:
 222        if (ib->outpos < ib->outlen) {
 223            ret = ib->outmsg[ib->outpos];
 224            ib->outpos++;
 225            if (ib->outpos == ib->outlen) {
 226                ib->outpos = 0;
 227                ib->outlen = 0;
 228            }
 229        } else {
 230            ret = 0xff;
 231        }
 232        break;
 233    case 2:
 234        ret = ib->mask_reg;
 235        break;
 236    }
 237    return ret;
 238}
 239
 240static void ipmi_bt_signal(IPMIBT *ib, IPMIInterface *ii)
 241{
 242    IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
 243
 244    ib->do_wake = 1;
 245    while (ib->do_wake) {
 246        ib->do_wake = 0;
 247        iic->handle_if_event(ii);
 248    }
 249}
 250
 251static void ipmi_bt_ioport_write(void *opaque, hwaddr addr, uint64_t val,
 252                                 unsigned size)
 253{
 254    IPMIInterface *ii = opaque;
 255    IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
 256    IPMIBT *ib = iic->get_backend_data(ii);
 257
 258    switch (addr & 3) {
 259    case 0:
 260        if (IPMI_BT_GET_CLR_WR(val)) {
 261            ib->inlen = 0;
 262        }
 263        if (IPMI_BT_GET_CLR_RD(val)) {
 264            ib->outpos = 0;
 265        }
 266        if (IPMI_BT_GET_B2H_ATN(val)) {
 267            IPMI_BT_SET_B2H_ATN(ib->control_reg, 0);
 268        }
 269        if (IPMI_BT_GET_SMS_ATN(val)) {
 270            IPMI_BT_SET_SMS_ATN(ib->control_reg, 0);
 271        }
 272        if (IPMI_BT_GET_HBUSY(val)) {
 273            /* Toggle */
 274            IPMI_BT_SET_HBUSY(ib->control_reg,
 275                              !IPMI_BT_GET_HBUSY(ib->control_reg));
 276        }
 277        if (IPMI_BT_GET_H2B_ATN(val)) {
 278            IPMI_BT_SET_BBUSY(ib->control_reg, 1);
 279            ipmi_bt_signal(ib, ii);
 280        }
 281        break;
 282
 283    case 1:
 284        if (ib->inlen < sizeof(ib->inmsg)) {
 285            ib->inmsg[ib->inlen] = val;
 286        }
 287        ib->inlen++;
 288        break;
 289
 290    case 2:
 291        if (IPMI_BT_GET_B2H_IRQ_EN(val) !=
 292                        IPMI_BT_GET_B2H_IRQ_EN(ib->mask_reg)) {
 293            if (IPMI_BT_GET_B2H_IRQ_EN(val)) {
 294                if (IPMI_BT_GET_B2H_ATN(ib->control_reg) ||
 295                        IPMI_BT_GET_SMS_ATN(ib->control_reg)) {
 296                    IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 1);
 297                    qemu_irq_raise(ib->irq);
 298                }
 299                IPMI_BT_SET_B2H_IRQ_EN(ib->mask_reg, 1);
 300            } else {
 301                if (IPMI_BT_GET_B2H_IRQ(ib->mask_reg)) {
 302                    IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 0);
 303                    qemu_irq_lower(ib->irq);
 304                }
 305                IPMI_BT_SET_B2H_IRQ_EN(ib->mask_reg, 0);
 306            }
 307        }
 308        if (IPMI_BT_GET_B2H_IRQ(val) && IPMI_BT_GET_B2H_IRQ(ib->mask_reg)) {
 309            IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 0);
 310            qemu_irq_lower(ib->irq);
 311        }
 312        break;
 313    }
 314}
 315
 316static const MemoryRegionOps ipmi_bt_io_ops = {
 317    .read = ipmi_bt_ioport_read,
 318    .write = ipmi_bt_ioport_write,
 319    .impl = {
 320        .min_access_size = 1,
 321        .max_access_size = 1,
 322    },
 323    .endianness = DEVICE_LITTLE_ENDIAN,
 324};
 325
 326static void ipmi_bt_set_atn(IPMIInterface *ii, int val, int irq)
 327{
 328    IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
 329    IPMIBT *ib = iic->get_backend_data(ii);
 330
 331    if (!!val == IPMI_BT_GET_SMS_ATN(ib->control_reg)) {
 332        return;
 333    }
 334
 335    IPMI_BT_SET_SMS_ATN(ib->control_reg, val);
 336    if (val) {
 337        if (irq && ib->use_irq && ib->irqs_enabled &&
 338                !IPMI_BT_GET_B2H_ATN(ib->control_reg) &&
 339                IPMI_BT_GET_B2H_IRQ_EN(ib->mask_reg)) {
 340            IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 1);
 341            qemu_irq_raise(ib->irq);
 342        }
 343    } else {
 344        if (!IPMI_BT_GET_B2H_ATN(ib->control_reg) &&
 345                IPMI_BT_GET_B2H_IRQ(ib->mask_reg)) {
 346            IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 0);
 347            qemu_irq_lower(ib->irq);
 348        }
 349    }
 350}
 351
 352static void ipmi_bt_handle_reset(IPMIInterface *ii, bool is_cold)
 353{
 354    IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
 355    IPMIBT *ib = iic->get_backend_data(ii);
 356
 357    if (is_cold) {
 358        /* Disable the BT interrupt on reset */
 359        if (IPMI_BT_GET_B2H_IRQ(ib->mask_reg)) {
 360            IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 0);
 361            qemu_irq_lower(ib->irq);
 362        }
 363        IPMI_BT_SET_B2H_IRQ_EN(ib->mask_reg, 0);
 364    }
 365}
 366
 367static void ipmi_bt_set_irq_enable(IPMIInterface *ii, int val)
 368{
 369    IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
 370    IPMIBT *ib = iic->get_backend_data(ii);
 371
 372    ib->irqs_enabled = val;
 373}
 374
 375static void ipmi_bt_init(IPMIInterface *ii, Error **errp)
 376{
 377    IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
 378    IPMIBT *ib = iic->get_backend_data(ii);
 379
 380    ib->io_length = 3;
 381
 382    memory_region_init_io(&ib->io, NULL, &ipmi_bt_io_ops, ii, "ipmi-bt", 3);
 383}
 384
 385
 386#define TYPE_ISA_IPMI_BT "isa-ipmi-bt"
 387#define ISA_IPMI_BT(obj) OBJECT_CHECK(ISAIPMIBTDevice, (obj), \
 388                                       TYPE_ISA_IPMI_BT)
 389
 390typedef struct ISAIPMIBTDevice {
 391    ISADevice dev;
 392    int32_t isairq;
 393    IPMIBT bt;
 394    uint32_t uuid;
 395} ISAIPMIBTDevice;
 396
 397static void ipmi_bt_get_fwinfo(struct IPMIInterface *ii, IPMIFwInfo *info)
 398{
 399    ISAIPMIBTDevice *iib = ISA_IPMI_BT(ii);
 400
 401    info->interface_name = "bt";
 402    info->interface_type = IPMI_SMBIOS_BT;
 403    info->ipmi_spec_major_revision = 2;
 404    info->ipmi_spec_minor_revision = 0;
 405    info->base_address = iib->bt.io_base;
 406    info->register_length = iib->bt.io_length;
 407    info->register_spacing = 1;
 408    info->memspace = IPMI_MEMSPACE_IO;
 409    info->irq_type = IPMI_LEVEL_IRQ;
 410    info->interrupt_number = iib->isairq;
 411    info->i2c_slave_address = iib->bt.bmc->slave_addr;
 412    info->uuid = iib->uuid;
 413}
 414
 415static void ipmi_bt_class_init(IPMIInterfaceClass *iic)
 416{
 417    iic->init = ipmi_bt_init;
 418    iic->set_atn = ipmi_bt_set_atn;
 419    iic->handle_rsp = ipmi_bt_handle_rsp;
 420    iic->handle_if_event = ipmi_bt_handle_event;
 421    iic->set_irq_enable = ipmi_bt_set_irq_enable;
 422    iic->reset = ipmi_bt_handle_reset;
 423    iic->get_fwinfo = ipmi_bt_get_fwinfo;
 424}
 425
 426static void isa_ipmi_bt_realize(DeviceState *dev, Error **errp)
 427{
 428    ISADevice *isadev = ISA_DEVICE(dev);
 429    ISAIPMIBTDevice *iib = ISA_IPMI_BT(dev);
 430    IPMIInterface *ii = IPMI_INTERFACE(dev);
 431    IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
 432
 433    if (!iib->bt.bmc) {
 434        error_setg(errp, "IPMI device requires a bmc attribute to be set");
 435        return;
 436    }
 437
 438    iib->uuid = ipmi_next_uuid();
 439
 440    iib->bt.bmc->intf = ii;
 441
 442    iic->init(ii, errp);
 443    if (*errp)
 444        return;
 445
 446    if (iib->isairq > 0) {
 447        isa_init_irq(isadev, &iib->bt.irq, iib->isairq);
 448        iib->bt.use_irq = 1;
 449    }
 450
 451    qdev_set_legacy_instance_id(dev, iib->bt.io_base, iib->bt.io_length);
 452
 453    isa_register_ioport(isadev, &iib->bt.io, iib->bt.io_base);
 454}
 455
 456static int ipmi_bt_vmstate_post_load(void *opaque, int version)
 457{
 458    IPMIBT *ib = opaque;
 459
 460    /* Make sure all the values are sane. */
 461    if (ib->outpos >= MAX_IPMI_MSG_SIZE || ib->outlen >= MAX_IPMI_MSG_SIZE ||
 462        ib->outpos >= ib->outlen) {
 463        qemu_log_mask(LOG_GUEST_ERROR,
 464                      "ipmi:bt: vmstate transfer received bad out values: %d %d\n",
 465                      ib->outpos, ib->outlen);
 466        ib->outpos = 0;
 467        ib->outlen = 0;
 468    }
 469
 470    if (ib->inlen >= MAX_IPMI_MSG_SIZE) {
 471        qemu_log_mask(LOG_GUEST_ERROR,
 472                      "ipmi:bt: vmstate transfer received bad in value: %d\n",
 473                      ib->inlen);
 474        ib->inlen = 0;
 475    }
 476
 477    return 0;
 478}
 479
 480const VMStateDescription vmstate_IPMIBT = {
 481    .name = TYPE_IPMI_INTERFACE_PREFIX "bt",
 482    .version_id = 1,
 483    .minimum_version_id = 1,
 484    .post_load = ipmi_bt_vmstate_post_load,
 485    .fields      = (VMStateField[]) {
 486        VMSTATE_BOOL(obf_irq_set, IPMIBT),
 487        VMSTATE_BOOL(atn_irq_set, IPMIBT),
 488        VMSTATE_BOOL(irqs_enabled, IPMIBT),
 489        VMSTATE_UINT32(outpos, IPMIBT),
 490        VMSTATE_UINT32(outlen, IPMIBT),
 491        VMSTATE_UINT8_ARRAY(outmsg, IPMIBT, MAX_IPMI_MSG_SIZE),
 492        VMSTATE_UINT32(inlen, IPMIBT),
 493        VMSTATE_UINT8_ARRAY(inmsg, IPMIBT, MAX_IPMI_MSG_SIZE),
 494        VMSTATE_UINT8(control_reg, IPMIBT),
 495        VMSTATE_UINT8(mask_reg, IPMIBT),
 496        VMSTATE_UINT8(waiting_rsp, IPMIBT),
 497        VMSTATE_UINT8(waiting_seq, IPMIBT),
 498        VMSTATE_END_OF_LIST()
 499    }
 500};
 501
 502static const VMStateDescription vmstate_ISAIPMIBTDevice = {
 503    .name = TYPE_IPMI_INTERFACE_PREFIX "isa-bt",
 504    .version_id = 2,
 505    .minimum_version_id = 2,
 506    /*
 507     * Version 1 had messed up the array transfer, it's not even usable
 508     * because it used VMSTATE_VBUFFER_UINT32, but it did not transfer
 509     * the buffer length, so random things would happen.
 510     */
 511    .fields      = (VMStateField[]) {
 512        VMSTATE_STRUCT(bt, ISAIPMIBTDevice, 1, vmstate_IPMIBT, IPMIBT),
 513        VMSTATE_END_OF_LIST()
 514    }
 515};
 516
 517static void isa_ipmi_bt_init(Object *obj)
 518{
 519    ISAIPMIBTDevice *iib = ISA_IPMI_BT(obj);
 520
 521    ipmi_bmc_find_and_link(obj, (Object **) &iib->bt.bmc);
 522
 523    vmstate_register(NULL, 0, &vmstate_ISAIPMIBTDevice, iib);
 524}
 525
 526static void *isa_ipmi_bt_get_backend_data(IPMIInterface *ii)
 527{
 528    ISAIPMIBTDevice *iib = ISA_IPMI_BT(ii);
 529
 530    return &iib->bt;
 531}
 532
 533static Property ipmi_isa_properties[] = {
 534    DEFINE_PROP_UINT32("ioport", ISAIPMIBTDevice, bt.io_base,  0xe4),
 535    DEFINE_PROP_INT32("irq",   ISAIPMIBTDevice, isairq,  5),
 536    DEFINE_PROP_END_OF_LIST(),
 537};
 538
 539static void isa_ipmi_bt_class_init(ObjectClass *oc, void *data)
 540{
 541    DeviceClass *dc = DEVICE_CLASS(oc);
 542    IPMIInterfaceClass *iic = IPMI_INTERFACE_CLASS(oc);
 543
 544    dc->realize = isa_ipmi_bt_realize;
 545    dc->props = ipmi_isa_properties;
 546
 547    iic->get_backend_data = isa_ipmi_bt_get_backend_data;
 548    ipmi_bt_class_init(iic);
 549}
 550
 551static const TypeInfo isa_ipmi_bt_info = {
 552    .name          = TYPE_ISA_IPMI_BT,
 553    .parent        = TYPE_ISA_DEVICE,
 554    .instance_size = sizeof(ISAIPMIBTDevice),
 555    .instance_init = isa_ipmi_bt_init,
 556    .class_init    = isa_ipmi_bt_class_init,
 557    .interfaces = (InterfaceInfo[]) {
 558        { TYPE_IPMI_INTERFACE },
 559        { }
 560    }
 561};
 562
 563static void ipmi_register_types(void)
 564{
 565    type_register_static(&isa_ipmi_bt_info);
 566}
 567
 568type_init(ipmi_register_types)
 569