diff mbox

[15/16] ipmi: Add ACPI table entries for BMCs

Message ID 1418411751-3614-16-git-send-email-minyard@acm.org
State New
Headers show

Commit Message

Corey Minyard Dec. 12, 2014, 7:15 p.m. UTC
From: Corey Minyard <cminyard@mvista.com>

Use the new ACPI table construction tools to create an ACPI
entry for IPMI.

Signed-off-by: Corey Minyard <cminyard@mvista.com>
---
 hw/ipmi/isa_ipmi.c | 145 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 145 insertions(+)

Comments

Benjamin Herrenschmidt Feb. 19, 2015, 2:54 a.m. UTC | #1
On Fri, 2014-12-12 at 13:15 -0600, minyard@acm.org wrote:
> From: Corey Minyard <cminyard@mvista.com>
> 
> Use the new ACPI table construction tools to create an ACPI
> entry for IPMI.

Same question as for the smbios business... Can this be made optional
possibly via instanciation attributes for the BMC device ?

Ben.

> Signed-off-by: Corey Minyard <cminyard@mvista.com>
> ---
>  hw/ipmi/isa_ipmi.c | 145 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 145 insertions(+)
> 
> diff --git a/hw/ipmi/isa_ipmi.c b/hw/ipmi/isa_ipmi.c
> index 83ea706..1652166 100644
> --- a/hw/ipmi/isa_ipmi.c
> +++ b/hw/ipmi/isa_ipmi.c
> @@ -23,6 +23,8 @@
>   */
>  #include "hw/hw.h"
>  #include "hw/isa/isa.h"
> +#include "hw/acpi/acpi-elements.h"
> +#include "hw/acpi/acpi.h"
>  #include "hw/i386/pc.h"
>  #include "qemu/timer.h"
>  #include "sysemu/char.h"
> @@ -39,6 +41,8 @@ typedef struct ISAIPMIDevice {
>      char *interface;
>      int intftype;
>      uint32_t iobase;
> +    uint32_t iolength;
> +    uint8_t regspacing;
>      int32 isairq;
>      uint8_t slave_addr;
>      uint8_t version;
> @@ -58,6 +62,143 @@ struct smbios_type_38 {
>      uint8_t interrupt_number;
>  } QEMU_PACKED;
>  
> +static int
> +acpi_ipmi_crs_ops(char **data, int dlen, void *opaque)
> +{
> +    ISAIPMIDevice *info = opaque;
> +    int len, rv;
> +    uint8_t regspacing = info->regspacing;
> +
> +    if (regspacing == 1) {
> +        regspacing = 0;
> +    }
> +
> +    /* IO(Decode16, x, y, z, c) */
> +    len = acpi_add_IO16(data, dlen, info->iobase,
> +                        info->iobase + info->iolength - 1,
> +                        regspacing, info->iolength);
> +    if (len < 0) {
> +        return len;
> +    }
> +
> +    if (info->isairq) {
> +        /* Interrupt(ResourceConsumer,Level,ActiveHigh,Exclusive) {n} */
> +        rv = acpi_add_Interrupt(data, dlen, info->isairq,
> +                                ACPI_RESOURCE_CONSUMER,
> +                                ACPI_INTERRUPT_MODE_LEVEL,
> +                                ACPI_INTERRUPT_POLARITY_ACTIVE_HIGH,
> +                                ACPI_INTERRUPT_EXCLUSIVE);
> +        if (rv < 0) {
> +            return rv;
> +        }
> +        len += rv;
> +    }
> +    rv = acpi_add_EndResource(data, dlen);
> +    if (rv < 0) {
> +        return rv;
> +    }
> +    len += rv;
> +    return len;
> +}
> +
> +static int
> +acpi_ipmi_crs(char **data, int dlen, void *opaque)
> +{
> +    ISAIPMIDevice *info = opaque;
> +    int len;
> +
> +    len = acpi_add_BufferOp(NULL, 0, acpi_ipmi_crs_ops, info);
> +    if (len < 0) {
> +        return len;
> +    }
> +    if (len <= dlen) {
> +        acpi_add_BufferOp(data, dlen, acpi_ipmi_crs_ops, info);
> +    }
> +    return len;
> +}
> +
> +static int
> +acpi_ipmi_dev(char **data, int dlen, void *opaque)
> +{
> +    ISAIPMIDevice *info = opaque;
> +    int len, rv;
> +    char *name;
> +    uint64_t val;
> +
> +    name = g_strdup_printf("ipmi_%s", info->interface);
> +
> +    /* Name(_HID, EISAID("IPI0001")) */
> +    len = acpi_add_Name(data, dlen, "_HID", acpi_add_EISAID,
> +                        (void *) "IPI0001");
> +    if (len < 0) {
> +        return len;
> +    }
> +    /* Name(_STR, Unicode("ipmi_xxx")) */
> +    rv = acpi_add_Name(data, dlen, "_STR", acpi_add_Unicode, name);
> +    if (rv < 0) {
> +        return rv;
> +    }
> +    len += rv;
> +    val = 0;
> +    /* Name(_UID, 0) */
> +    rv = acpi_add_Name(data, dlen, "_UID", acpi_add_Integer, &val);
> +    if (rv < 0) {
> +        return rv;
> +    }
> +    len += rv;
> +    /* Name(_CRS, ResourceTemplate() { */
> +    rv = acpi_add_Name(data, dlen, "_CRS", acpi_ipmi_crs, info);
> +    if (rv < 0) {
> +        return rv;
> +    }
> +    len += rv;
> +    val = info->intftype;
> +    /* Method(_IFT) { Return(i) } */
> +    rv = acpi_add_Method(data, dlen, "_IFT", 0, acpi_add_Return, &val);
> +    if (rv < 0) {
> +        return rv;
> +    }
> +    len += rv;
> +    val = ((info->version & 0xf0) << 4) | (info->version & 0x0f);
> +    /* Method(_SRV) { Return(version) } */
> +    rv = acpi_add_Method(data, dlen, "_SRV", 0, acpi_add_Return, &val);
> +    if (rv < 0) {
> +        return rv;
> +    }
> +    len += rv;
> +    return len;
> +}
> +
> +static int
> +acpi_ipmi_scope(char **data, int dlen, void *opaque)
> +{
> +    ISAIPMIDevice *info = opaque;
> +
> +    /* Device(MI0) { */
> +    return acpi_add_Device(data, dlen, "MI0", acpi_ipmi_dev, info);
> +    /* } */
> +}
> +
> +static void
> +ipmi_encode_acpi(ISAIPMIDevice *info)
> +{
> +    char ipmitable[200];
> +    char *tblptr = ipmitable;
> +    int rc;
> +    Error *err = NULL;
> +
> +    /* Scope(\_SB.PCI0.ISA) { */
> +    rc = acpi_add_Scope(&tblptr, sizeof(ipmitable), "\\_SB.PCI0.ISA",
> +                         acpi_ipmi_scope, info);
> +    /* } */
> +    if (rc < 0) {
> +        fprintf(stderr, "Unable to format IPMI ACPI table entry\n");
> +        return;
> +    }
> +
> +    acpi_append_to_table("SSDT", ipmitable, rc, &err);
> +}
> +
>  static void ipmi_encode_smbios(void *opaque)
>  {
>      ISAIPMIDevice *info = opaque;
> @@ -79,6 +220,8 @@ static void ipmi_encode_smbios(void *opaque)
>      smb38.interrupt_number = info->isairq;
>      smbios_table_entry_add((struct smbios_structure_header *) &smb38,
>                             sizeof(smb38), true);
> +
> +    ipmi_encode_acpi(info);
>  }
>  
>  static void ipmi_isa_realizefn(DeviceState *dev, Error **errp)
> @@ -110,6 +253,7 @@ static void ipmi_isa_realizefn(DeviceState *dev, Error **errp)
>      intfk = IPMI_INTERFACE_GET_CLASS(intf);
>      bmc->intf = intf;
>      intf->bmc = bmc;
> +    ipmi->regspacing = 1;
>      intf->io_base = ipmi->iobase;
>      intf->slave_addr = ipmi->slave_addr;
>      ipmi->intftype = intfk->smbios_type;
> @@ -118,6 +262,7 @@ static void ipmi_isa_realizefn(DeviceState *dev, Error **errp)
>      if (*errp) {
>          return;
>      }
> +    ipmi->iolength = intf->io_length;
>      ipmi_bmc_init(bmc, errp);
>      if (*errp) {
>          return;
Corey Minyard Feb. 20, 2015, 3:16 a.m. UTC | #2
On 02/18/2015 08:54 PM, Benjamin Herrenschmidt wrote:
> On Fri, 2014-12-12 at 13:15 -0600, minyard@acm.org wrote:
>> From: Corey Minyard <cminyard@mvista.com>
>>
>> Use the new ACPI table construction tools to create an ACPI
>> entry for IPMI.
> Same question as for the smbios business... Can this be made optional
> possibly via instanciation attributes for the BMC device ?

I was thinking about how to do this.  I wasn't too terribly concerned
right now because none of this ACPI stuff is going in as is, there are
other patches for handling this and there's a lot to work out for SMBIOS
and ACPI.

However, there is another pressing concern, assuming your device is on
the ISA bus, and that's the default address, interrupt, etc.  It may
vary from platform to platform, and it would be nice to have a way for
it to be set more automatically.

If it's not on an ISA bus, another interface will need to be written.

-corey

> Ben.
>
>> Signed-off-by: Corey Minyard <cminyard@mvista.com>
>> ---
>>  hw/ipmi/isa_ipmi.c | 145 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 145 insertions(+)
>>
>> diff --git a/hw/ipmi/isa_ipmi.c b/hw/ipmi/isa_ipmi.c
>> index 83ea706..1652166 100644
>> --- a/hw/ipmi/isa_ipmi.c
>> +++ b/hw/ipmi/isa_ipmi.c
>> @@ -23,6 +23,8 @@
>>   */
>>  #include "hw/hw.h"
>>  #include "hw/isa/isa.h"
>> +#include "hw/acpi/acpi-elements.h"
>> +#include "hw/acpi/acpi.h"
>>  #include "hw/i386/pc.h"
>>  #include "qemu/timer.h"
>>  #include "sysemu/char.h"
>> @@ -39,6 +41,8 @@ typedef struct ISAIPMIDevice {
>>      char *interface;
>>      int intftype;
>>      uint32_t iobase;
>> +    uint32_t iolength;
>> +    uint8_t regspacing;
>>      int32 isairq;
>>      uint8_t slave_addr;
>>      uint8_t version;
>> @@ -58,6 +62,143 @@ struct smbios_type_38 {
>>      uint8_t interrupt_number;
>>  } QEMU_PACKED;
>>  
>> +static int
>> +acpi_ipmi_crs_ops(char **data, int dlen, void *opaque)
>> +{
>> +    ISAIPMIDevice *info = opaque;
>> +    int len, rv;
>> +    uint8_t regspacing = info->regspacing;
>> +
>> +    if (regspacing == 1) {
>> +        regspacing = 0;
>> +    }
>> +
>> +    /* IO(Decode16, x, y, z, c) */
>> +    len = acpi_add_IO16(data, dlen, info->iobase,
>> +                        info->iobase + info->iolength - 1,
>> +                        regspacing, info->iolength);
>> +    if (len < 0) {
>> +        return len;
>> +    }
>> +
>> +    if (info->isairq) {
>> +        /* Interrupt(ResourceConsumer,Level,ActiveHigh,Exclusive) {n} */
>> +        rv = acpi_add_Interrupt(data, dlen, info->isairq,
>> +                                ACPI_RESOURCE_CONSUMER,
>> +                                ACPI_INTERRUPT_MODE_LEVEL,
>> +                                ACPI_INTERRUPT_POLARITY_ACTIVE_HIGH,
>> +                                ACPI_INTERRUPT_EXCLUSIVE);
>> +        if (rv < 0) {
>> +            return rv;
>> +        }
>> +        len += rv;
>> +    }
>> +    rv = acpi_add_EndResource(data, dlen);
>> +    if (rv < 0) {
>> +        return rv;
>> +    }
>> +    len += rv;
>> +    return len;
>> +}
>> +
>> +static int
>> +acpi_ipmi_crs(char **data, int dlen, void *opaque)
>> +{
>> +    ISAIPMIDevice *info = opaque;
>> +    int len;
>> +
>> +    len = acpi_add_BufferOp(NULL, 0, acpi_ipmi_crs_ops, info);
>> +    if (len < 0) {
>> +        return len;
>> +    }
>> +    if (len <= dlen) {
>> +        acpi_add_BufferOp(data, dlen, acpi_ipmi_crs_ops, info);
>> +    }
>> +    return len;
>> +}
>> +
>> +static int
>> +acpi_ipmi_dev(char **data, int dlen, void *opaque)
>> +{
>> +    ISAIPMIDevice *info = opaque;
>> +    int len, rv;
>> +    char *name;
>> +    uint64_t val;
>> +
>> +    name = g_strdup_printf("ipmi_%s", info->interface);
>> +
>> +    /* Name(_HID, EISAID("IPI0001")) */
>> +    len = acpi_add_Name(data, dlen, "_HID", acpi_add_EISAID,
>> +                        (void *) "IPI0001");
>> +    if (len < 0) {
>> +        return len;
>> +    }
>> +    /* Name(_STR, Unicode("ipmi_xxx")) */
>> +    rv = acpi_add_Name(data, dlen, "_STR", acpi_add_Unicode, name);
>> +    if (rv < 0) {
>> +        return rv;
>> +    }
>> +    len += rv;
>> +    val = 0;
>> +    /* Name(_UID, 0) */
>> +    rv = acpi_add_Name(data, dlen, "_UID", acpi_add_Integer, &val);
>> +    if (rv < 0) {
>> +        return rv;
>> +    }
>> +    len += rv;
>> +    /* Name(_CRS, ResourceTemplate() { */
>> +    rv = acpi_add_Name(data, dlen, "_CRS", acpi_ipmi_crs, info);
>> +    if (rv < 0) {
>> +        return rv;
>> +    }
>> +    len += rv;
>> +    val = info->intftype;
>> +    /* Method(_IFT) { Return(i) } */
>> +    rv = acpi_add_Method(data, dlen, "_IFT", 0, acpi_add_Return, &val);
>> +    if (rv < 0) {
>> +        return rv;
>> +    }
>> +    len += rv;
>> +    val = ((info->version & 0xf0) << 4) | (info->version & 0x0f);
>> +    /* Method(_SRV) { Return(version) } */
>> +    rv = acpi_add_Method(data, dlen, "_SRV", 0, acpi_add_Return, &val);
>> +    if (rv < 0) {
>> +        return rv;
>> +    }
>> +    len += rv;
>> +    return len;
>> +}
>> +
>> +static int
>> +acpi_ipmi_scope(char **data, int dlen, void *opaque)
>> +{
>> +    ISAIPMIDevice *info = opaque;
>> +
>> +    /* Device(MI0) { */
>> +    return acpi_add_Device(data, dlen, "MI0", acpi_ipmi_dev, info);
>> +    /* } */
>> +}
>> +
>> +static void
>> +ipmi_encode_acpi(ISAIPMIDevice *info)
>> +{
>> +    char ipmitable[200];
>> +    char *tblptr = ipmitable;
>> +    int rc;
>> +    Error *err = NULL;
>> +
>> +    /* Scope(\_SB.PCI0.ISA) { */
>> +    rc = acpi_add_Scope(&tblptr, sizeof(ipmitable), "\\_SB.PCI0.ISA",
>> +                         acpi_ipmi_scope, info);
>> +    /* } */
>> +    if (rc < 0) {
>> +        fprintf(stderr, "Unable to format IPMI ACPI table entry\n");
>> +        return;
>> +    }
>> +
>> +    acpi_append_to_table("SSDT", ipmitable, rc, &err);
>> +}
>> +
>>  static void ipmi_encode_smbios(void *opaque)
>>  {
>>      ISAIPMIDevice *info = opaque;
>> @@ -79,6 +220,8 @@ static void ipmi_encode_smbios(void *opaque)
>>      smb38.interrupt_number = info->isairq;
>>      smbios_table_entry_add((struct smbios_structure_header *) &smb38,
>>                             sizeof(smb38), true);
>> +
>> +    ipmi_encode_acpi(info);
>>  }
>>  
>>  static void ipmi_isa_realizefn(DeviceState *dev, Error **errp)
>> @@ -110,6 +253,7 @@ static void ipmi_isa_realizefn(DeviceState *dev, Error **errp)
>>      intfk = IPMI_INTERFACE_GET_CLASS(intf);
>>      bmc->intf = intf;
>>      intf->bmc = bmc;
>> +    ipmi->regspacing = 1;
>>      intf->io_base = ipmi->iobase;
>>      intf->slave_addr = ipmi->slave_addr;
>>      ipmi->intftype = intfk->smbios_type;
>> @@ -118,6 +262,7 @@ static void ipmi_isa_realizefn(DeviceState *dev, Error **errp)
>>      if (*errp) {
>>          return;
>>      }
>> +    ipmi->iolength = intf->io_length;
>>      ipmi_bmc_init(bmc, errp);
>>      if (*errp) {
>>          return;
>
>
Benjamin Herrenschmidt Feb. 22, 2015, 8:48 p.m. UTC | #3
On Thu, 2015-02-19 at 21:16 -0600, Corey Minyard wrote:
> However, there is another pressing concern, assuming your device is on
> the ISA bus, and that's the default address, interrupt, etc.  It may
> vary from platform to platform, and it would be nice to have a way for
> it to be set more automatically.
> 
> If it's not on an ISA bus, another interface will need to be written.

It's on the LPC/ISA bus, and the address/interrupt are in the
device-tree which qemu provides but yes, it would make sense to have
them be qdev properties to configure them to mimmic actual HW.

In fact I would like them to be qobject properties that can be changed
at runtime, but I'll look into that later. The reason is that I want to
emulate a bit more of the BMC since our FW uses a few other things in
there, and among others, some registers that you can use to ...
set/change the ISA address of the BT or KCS interfaces. (In fact same
goes with the UART).

But that's for much later, I still have a lot of work to do to get the
basic shape of the P8 model in a mergable state, so my comment was more
a generic idea of trying to keep the more generic BMC bits reasonably
separate from the SMBIOS/ACPI specific portions.

Cheers,
Ben.
diff mbox

Patch

diff --git a/hw/ipmi/isa_ipmi.c b/hw/ipmi/isa_ipmi.c
index 83ea706..1652166 100644
--- a/hw/ipmi/isa_ipmi.c
+++ b/hw/ipmi/isa_ipmi.c
@@ -23,6 +23,8 @@ 
  */
 #include "hw/hw.h"
 #include "hw/isa/isa.h"
+#include "hw/acpi/acpi-elements.h"
+#include "hw/acpi/acpi.h"
 #include "hw/i386/pc.h"
 #include "qemu/timer.h"
 #include "sysemu/char.h"
@@ -39,6 +41,8 @@  typedef struct ISAIPMIDevice {
     char *interface;
     int intftype;
     uint32_t iobase;
+    uint32_t iolength;
+    uint8_t regspacing;
     int32 isairq;
     uint8_t slave_addr;
     uint8_t version;
@@ -58,6 +62,143 @@  struct smbios_type_38 {
     uint8_t interrupt_number;
 } QEMU_PACKED;
 
+static int
+acpi_ipmi_crs_ops(char **data, int dlen, void *opaque)
+{
+    ISAIPMIDevice *info = opaque;
+    int len, rv;
+    uint8_t regspacing = info->regspacing;
+
+    if (regspacing == 1) {
+        regspacing = 0;
+    }
+
+    /* IO(Decode16, x, y, z, c) */
+    len = acpi_add_IO16(data, dlen, info->iobase,
+                        info->iobase + info->iolength - 1,
+                        regspacing, info->iolength);
+    if (len < 0) {
+        return len;
+    }
+
+    if (info->isairq) {
+        /* Interrupt(ResourceConsumer,Level,ActiveHigh,Exclusive) {n} */
+        rv = acpi_add_Interrupt(data, dlen, info->isairq,
+                                ACPI_RESOURCE_CONSUMER,
+                                ACPI_INTERRUPT_MODE_LEVEL,
+                                ACPI_INTERRUPT_POLARITY_ACTIVE_HIGH,
+                                ACPI_INTERRUPT_EXCLUSIVE);
+        if (rv < 0) {
+            return rv;
+        }
+        len += rv;
+    }
+    rv = acpi_add_EndResource(data, dlen);
+    if (rv < 0) {
+        return rv;
+    }
+    len += rv;
+    return len;
+}
+
+static int
+acpi_ipmi_crs(char **data, int dlen, void *opaque)
+{
+    ISAIPMIDevice *info = opaque;
+    int len;
+
+    len = acpi_add_BufferOp(NULL, 0, acpi_ipmi_crs_ops, info);
+    if (len < 0) {
+        return len;
+    }
+    if (len <= dlen) {
+        acpi_add_BufferOp(data, dlen, acpi_ipmi_crs_ops, info);
+    }
+    return len;
+}
+
+static int
+acpi_ipmi_dev(char **data, int dlen, void *opaque)
+{
+    ISAIPMIDevice *info = opaque;
+    int len, rv;
+    char *name;
+    uint64_t val;
+
+    name = g_strdup_printf("ipmi_%s", info->interface);
+
+    /* Name(_HID, EISAID("IPI0001")) */
+    len = acpi_add_Name(data, dlen, "_HID", acpi_add_EISAID,
+                        (void *) "IPI0001");
+    if (len < 0) {
+        return len;
+    }
+    /* Name(_STR, Unicode("ipmi_xxx")) */
+    rv = acpi_add_Name(data, dlen, "_STR", acpi_add_Unicode, name);
+    if (rv < 0) {
+        return rv;
+    }
+    len += rv;
+    val = 0;
+    /* Name(_UID, 0) */
+    rv = acpi_add_Name(data, dlen, "_UID", acpi_add_Integer, &val);
+    if (rv < 0) {
+        return rv;
+    }
+    len += rv;
+    /* Name(_CRS, ResourceTemplate() { */
+    rv = acpi_add_Name(data, dlen, "_CRS", acpi_ipmi_crs, info);
+    if (rv < 0) {
+        return rv;
+    }
+    len += rv;
+    val = info->intftype;
+    /* Method(_IFT) { Return(i) } */
+    rv = acpi_add_Method(data, dlen, "_IFT", 0, acpi_add_Return, &val);
+    if (rv < 0) {
+        return rv;
+    }
+    len += rv;
+    val = ((info->version & 0xf0) << 4) | (info->version & 0x0f);
+    /* Method(_SRV) { Return(version) } */
+    rv = acpi_add_Method(data, dlen, "_SRV", 0, acpi_add_Return, &val);
+    if (rv < 0) {
+        return rv;
+    }
+    len += rv;
+    return len;
+}
+
+static int
+acpi_ipmi_scope(char **data, int dlen, void *opaque)
+{
+    ISAIPMIDevice *info = opaque;
+
+    /* Device(MI0) { */
+    return acpi_add_Device(data, dlen, "MI0", acpi_ipmi_dev, info);
+    /* } */
+}
+
+static void
+ipmi_encode_acpi(ISAIPMIDevice *info)
+{
+    char ipmitable[200];
+    char *tblptr = ipmitable;
+    int rc;
+    Error *err = NULL;
+
+    /* Scope(\_SB.PCI0.ISA) { */
+    rc = acpi_add_Scope(&tblptr, sizeof(ipmitable), "\\_SB.PCI0.ISA",
+                         acpi_ipmi_scope, info);
+    /* } */
+    if (rc < 0) {
+        fprintf(stderr, "Unable to format IPMI ACPI table entry\n");
+        return;
+    }
+
+    acpi_append_to_table("SSDT", ipmitable, rc, &err);
+}
+
 static void ipmi_encode_smbios(void *opaque)
 {
     ISAIPMIDevice *info = opaque;
@@ -79,6 +220,8 @@  static void ipmi_encode_smbios(void *opaque)
     smb38.interrupt_number = info->isairq;
     smbios_table_entry_add((struct smbios_structure_header *) &smb38,
                            sizeof(smb38), true);
+
+    ipmi_encode_acpi(info);
 }
 
 static void ipmi_isa_realizefn(DeviceState *dev, Error **errp)
@@ -110,6 +253,7 @@  static void ipmi_isa_realizefn(DeviceState *dev, Error **errp)
     intfk = IPMI_INTERFACE_GET_CLASS(intf);
     bmc->intf = intf;
     intf->bmc = bmc;
+    ipmi->regspacing = 1;
     intf->io_base = ipmi->iobase;
     intf->slave_addr = ipmi->slave_addr;
     ipmi->intftype = intfk->smbios_type;
@@ -118,6 +262,7 @@  static void ipmi_isa_realizefn(DeviceState *dev, Error **errp)
     if (*errp) {
         return;
     }
+    ipmi->iolength = intf->io_length;
     ipmi_bmc_init(bmc, errp);
     if (*errp) {
         return;