Patchwork [12/16] IPMI: Add a PC ISA type structure

login
register
mail settings
Submitter Corey Minyard
Date July 15, 2012, 8:25 p.m.
Message ID <1342383911-6094-12-git-send-email-minyard@acm.org>
Download mbox | patch
Permalink /patch/171097/
State New
Headers show

Comments

Corey Minyard - July 15, 2012, 8:25 p.m.
From: Corey Minyard <cminyard@mvista.com>

This provides the base infrastructure to tie IPMI low-level
interfaces into a PC ISA bus.

Signed-off-by: Corey Minyard <cminyard@mvista.com>
---
 default-configs/i386-softmmu.mak   |    1 +
 default-configs/x86_64-softmmu.mak |    1 +
 hw/Makefile.objs                   |    1 +
 hw/isa_ipmi.c                      |  156 ++++++++++++++++++++++++++++++++++++
 hw/smbios.h                        |   12 +++
 5 files changed, 171 insertions(+), 0 deletions(-)
 create mode 100644 hw/isa_ipmi.c
Paolo Bonzini - July 16, 2012, 7:16 a.m.
Il 15/07/2012 22:25, minyard@acm.org ha scritto:
> +    /* Clear the property from this device so we can put it elsewhere */
> +    chr = isa->chr;
> +    qdev_prop_set_chr(&dev->qdev, "chardev", NULL);
> +
> +    if (chr) {
> +	bdev = qdev_create(NULL, "ipmi-bmc-extern");
> +	qdev_prop_set_chr(bdev, "chardev", chr);
> +    } else {
> +	bdev = qdev_create(NULL, "ipmi-bmc-sim");
> +    }
> +    snprintf(typename, sizeof(typename), "ipmi-interface-%s", isa->interface);
> +    idev = qdev_create(&isa_bus->qbus, typename);
> +    qdev_prop_set_ptr(bdev, "ipmiif", idev);
> +    qdev_prop_set_uint64(idev, "iobase", isa->iobase);
> +    qdev_prop_set_ptr(idev, "bmc", bdev);
> +    qdev_prop_set_uint8(idev, "slave-addr", isa->slave_addr);
> +    rc = qdev_init(idev);

I think this is adding a bit of extra complication.  You do not need to
add explicit devices for this.

If you want to make ipmi-bmc-* and ipmi-interface-* objects, you can
create them with object_new, set the properties manually with the
returned pointer and add the object to the parent with
object_property_add_child.

Otherwise, it should also be fine if you just add them as function pointers.

Either way also lets you keep the ownership of the chardev in the ISA
IPMI device, and avoids that "info qtree" looks strange and does not
show the chardev you assigned.

Paolo
Corey Minyard - July 17, 2012, 12:16 a.m.
On 07/16/2012 02:16 AM, Paolo Bonzini wrote:
> Il 15/07/2012 22:25, minyard@acm.org ha scritto:
>> +    /* Clear the property from this device so we can put it elsewhere */
>> +    chr = isa->chr;
>> +    qdev_prop_set_chr(&dev->qdev, "chardev", NULL);
>> +
>> +    if (chr) {
>> +	bdev = qdev_create(NULL, "ipmi-bmc-extern");
>> +	qdev_prop_set_chr(bdev, "chardev", chr);
>> +    } else {
>> +	bdev = qdev_create(NULL, "ipmi-bmc-sim");
>> +    }
>> +    snprintf(typename, sizeof(typename), "ipmi-interface-%s", isa->interface);
>> +    idev = qdev_create(&isa_bus->qbus, typename);
>> +    qdev_prop_set_ptr(bdev, "ipmiif", idev);
>> +    qdev_prop_set_uint64(idev, "iobase", isa->iobase);
>> +    qdev_prop_set_ptr(idev, "bmc", bdev);
>> +    qdev_prop_set_uint8(idev, "slave-addr", isa->slave_addr);
>> +    rc = qdev_init(idev);
> I think this is adding a bit of extra complication.  You do not need to
> add explicit devices for this.

Yeah, but the qdevs did a lot of nice things for me :).  But I understand.

>
> If you want to make ipmi-bmc-* and ipmi-interface-* objects, you can
> create them with object_new, set the properties manually with the
> returned pointer and add the object to the parent with
> object_property_add_child.

The main reason I went with qdevs originally was because all the 
properties are defined for qdevs.  I'd have to do all my own properties 
otherwise.

However, I think all the properties are represented by what is already 
there in isa-ipmi, so just having pointers to the interface and bmc 
objects is ok, I think.

>
> Otherwise, it should also be fine if you just add them as function pointers.
>
> Either way also lets you keep the ownership of the chardev in the ISA
> IPMI device, and avoids that "info qtree" looks strange and does not
> show the chardev you assigned.

Yeah, I see that now.  Makes sense.

BTW, where do you want me to document this?  I didn't see an obvious 
place in qemu-options.hx.

I'm working on tests, too.  I didn't find much there already, but I'll 
see what I can add.

Thanks,

-corey

Patch

diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak
index eb17afc..c0aff0d 100644
--- a/default-configs/i386-softmmu.mak
+++ b/default-configs/i386-softmmu.mak
@@ -8,6 +8,7 @@  CONFIG_VGA_CIRRUS=y
 CONFIG_VMWARE_VGA=y
 CONFIG_VMMOUSE=y
 CONFIG_IPMI=y
+CONFIG_ISA_IPMI=y
 CONFIG_SERIAL=y
 CONFIG_PARALLEL=y
 CONFIG_I8254=y
diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak
index e4e3e4f..615e4f2 100644
--- a/default-configs/x86_64-softmmu.mak
+++ b/default-configs/x86_64-softmmu.mak
@@ -8,6 +8,7 @@  CONFIG_VGA_CIRRUS=y
 CONFIG_VMWARE_VGA=y
 CONFIG_VMMOUSE=y
 CONFIG_IPMI=y
+CONFIG_ISA_IPMI=y
 CONFIG_SERIAL=y
 CONFIG_PARALLEL=y
 CONFIG_I8254=y
diff --git a/hw/Makefile.objs b/hw/Makefile.objs
index 256cfae..928870b 100644
--- a/hw/Makefile.objs
+++ b/hw/Makefile.objs
@@ -21,6 +21,7 @@  hw-obj-$(CONFIG_ESCC) += escc.o
 hw-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o
 
 hw-obj-$(CONFIG_IPMI) += ipmi.o
+hw-obj-$(CONFIG_ISA_IPMI) += isa_ipmi.o
 
 hw-obj-$(CONFIG_SERIAL) += serial.o
 hw-obj-$(CONFIG_PARALLEL) += parallel.o
diff --git a/hw/isa_ipmi.c b/hw/isa_ipmi.c
new file mode 100644
index 0000000..a3ca558
--- /dev/null
+++ b/hw/isa_ipmi.c
@@ -0,0 +1,156 @@ 
+/*
+ * QEMU ISA IPMI KCS emulation
+ *
+ * Copyright (c) 2012 Corey Minyard, MontaVista Software, LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "hw.h"
+#include "isa.h"
+#include "pc.h"
+#include "qemu-timer.h"
+#include "qemu-char.h"
+#include "sysemu.h"
+#include "smbios.h"
+#include "ipmi.h"
+
+
+typedef struct ISAIPMIDevice {
+    ISADevice dev;
+    char *interface;
+    uint32_t iobase;
+    uint32_t isairq;
+    uint8_t slave_addr;
+    CharDriverState *chr;
+} ISAIPMIDevice;
+
+static int ipmi_isa_initfn(ISADevice *dev)
+{
+    ISAIPMIDevice *isa = DO_UPCAST(ISAIPMIDevice, dev, dev);
+    IPMIDeviceClass *k;
+    IPMIDevice *s;
+    struct smbios_type_38 smb38;
+    char typename[20];
+    DeviceState *idev;
+    DeviceState *bdev;
+    ISABus *isa_bus = isa_bus_from_device(dev);
+    int rc;
+    CharDriverState *chr;
+
+    if (!isa->interface)
+	isa->interface = g_strdup("kcs");
+
+    /* Clear the property from this device so we can put it elsewhere */
+    chr = isa->chr;
+    qdev_prop_set_chr(&dev->qdev, "chardev", NULL);
+
+    if (chr) {
+	bdev = qdev_create(NULL, "ipmi-bmc-extern");
+	qdev_prop_set_chr(bdev, "chardev", chr);
+    } else {
+	bdev = qdev_create(NULL, "ipmi-bmc-sim");
+    }
+    snprintf(typename, sizeof(typename), "ipmi-interface-%s", isa->interface);
+    idev = qdev_create(&isa_bus->qbus, typename);
+    qdev_prop_set_ptr(bdev, "ipmiif", idev);
+    qdev_prop_set_uint64(idev, "iobase", isa->iobase);
+    qdev_prop_set_ptr(idev, "bmc", bdev);
+    qdev_prop_set_uint8(idev, "slave-addr", isa->slave_addr);
+    rc = qdev_init(idev);
+    if (rc)
+	return rc;
+    rc = qdev_init(bdev);
+    if (rc)
+	return rc;
+
+    k = IPMI_DEVICE_GET_CLASS(idev);
+    s = IPMI_DEVICE(idev);
+
+    if (isa->isairq != 0) {
+	isa_init_irq(dev, &s->irq, isa->isairq);
+	s->use_irq = 1;
+    }
+
+    qdev_set_legacy_instance_id(&dev->qdev, s->io_base, s->io_length);
+
+    isa_register_ioport(dev, &s->io, s->io_base);
+
+    smb38.header.type = 38;
+    smb38.header.length = sizeof(smb38);
+    smb38.header.handle = 0x3000;
+    smb38.interface_type = k->smbios_type;
+    smb38.ipmi_version = 0x20;
+    smb38.i2c_slave_addr = s->slave_addr;
+    smb38.nv_storage_dev_addr = 0;
+
+    /* or 1 to set it to I/O space */
+    smb38.base_addr = s->io_base | 1;
+
+     /* 1-byte boundaries, addr bit0=0, level triggered irq */
+    smb38.base_addr_mod_and_irq_info = 1;
+    smb38.interrupt_number = isa->isairq;
+    smbios_table_entry_add((struct smbios_structure_header *) &smb38);
+
+    return 0;
+}
+
+static Property ipmi_isa_properties[] = {
+    DEFINE_PROP_STRING("interface", ISAIPMIDevice, interface),
+    DEFINE_PROP_HEX32("iobase", ISAIPMIDevice, iobase,  0),
+    DEFINE_PROP_UINT32("irq",   ISAIPMIDevice, isairq,  5),
+    DEFINE_PROP_UINT8("slave_addr", ISAIPMIDevice, slave_addr,  0),
+    DEFINE_PROP_CHR("chardev",  ISAIPMIDevice, chr),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+#if 0 /* FIXME */
+static const VMStateDescription vmstate_isa_ipmi = {
+    .name = "isa-ipmi",
+    .version_id = 3,
+    .minimum_version_id = 3,
+    .fields      = (VMStateField []) {
+	/* FIXME - fill this in */
+        VMSTATE_END_OF_LIST()
+    }
+};
+#endif
+
+static void ipmi_isa_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = ipmi_isa_initfn;
+    //dc->vmsd = &vmstate_isa_ipmi;
+    dc->props = ipmi_isa_properties;
+}
+
+static TypeInfo ipmi_isa_info = {
+    .name          = "isa-ipmi",
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof(ISAIPMIDevice),
+    .class_init    = ipmi_isa_class_initfn,
+};
+
+static void ipmi_register_types(void)
+{
+    type_register_static(&ipmi_isa_info);
+    qdev_add_prefw_init("isa-ipmi");
+}
+
+type_init(ipmi_register_types)
diff --git a/hw/smbios.h b/hw/smbios.h
index 6431a15..b9e4a61 100644
--- a/hw/smbios.h
+++ b/hw/smbios.h
@@ -155,6 +155,18 @@  struct smbios_type_32 {
     uint8_t boot_status;
 } QEMU_PACKED;
 
+/* SMBIOS type 38 - IPMI Device Information */
+struct smbios_type_38 {
+    struct smbios_structure_header header;
+    uint8_t interface_type;
+    uint8_t ipmi_version;
+    uint8_t i2c_slave_addr;
+    uint8_t nv_storage_dev_addr;
+    uint64_t base_addr;
+    uint8_t base_addr_mod_and_irq_info;
+    uint8_t interrupt_number;
+} QEMU_PACKED;
+
 /* SMBIOS type 127 -- End-of-table */
 struct smbios_type_127 {
     struct smbios_structure_header header;