From: Corey Minyard <[email protected]> Use the new ACPI table construction tools to create an ACPI entry for IPMI.
Signed-off-by: Corey Minyard <[email protected]> --- hw/ipmi/isa_ipmi.c | 127 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/hw/ipmi/isa_ipmi.c b/hw/ipmi/isa_ipmi.c index 7664b66..92afb88 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" @@ -36,16 +38,134 @@ typedef struct ISAIPMIDevice { ISADevice dev; char *interface; + int intftype; uint32_t iobase; + uint32_t endaddr; uint32_t isairq; + uint8_t regspacing; uint8_t slave_addr; + uint8_t version; CharDriverState *chr; IPMIInterface *intf; } ISAIPMIDevice; +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->endaddr, + regspacing, info->endaddr - info->iobase + 1); + 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 void +ipmi_encode_acpi(ISAIPMIDevice *info) +{ + char ipmitable[200]; + char *tblptr = ipmitable; + int rc; + Error *err = NULL; + + /* Device(MI0) { */ + rc = acpi_add_Device(&tblptr, sizeof(ipmitable), "MI0", + acpi_ipmi_dev, info); + /* } */ + if (rc < 0) { + fprintf(stderr, "Unable to format IPMI ACPI table entry\n"); + return; + } + + acpi_append_to_table("DSDT", ipmitable, rc, &err); +} + static int ipmi_isa_initfn(ISADevice *dev) { ISAIPMIDevice *isa = ISA_IPMI(dev); + IPMIInterfaceClass *intfk; char typename[20]; Object *intfobj; IPMIInterface *intf; @@ -69,6 +189,7 @@ static int ipmi_isa_initfn(ISADevice *dev) TYPE_IPMI_INTERFACE_PREFIX "%s", isa->interface); intfobj = object_new(typename); intf = IPMI_INTERFACE(intfobj); + intfk = IPMI_INTERFACE_GET_CLASS(intf); bmc->intf = intf; intf->bmc = bmc; intf->io_base = isa->iobase; @@ -85,6 +206,10 @@ static int ipmi_isa_initfn(ISADevice *dev) /* These may be set by the interface. */ isa->iobase = intf->io_base; isa->slave_addr = intf->slave_addr; + isa->regspacing = 1; + isa->endaddr = cpu_to_le64(intf->io_base + intf->io_length - 1); + isa->intftype = intfk->smbios_type; + isa->version = 0x20; /* Version 2.0 */ if (isa->isairq != 0) { isa_init_irq(dev, &intf->irq, isa->isairq); @@ -107,6 +232,8 @@ static int ipmi_isa_initfn(ISADevice *dev) isa_register_ioport(dev, &intf->io, intf->io_base); + ipmi_encode_acpi(isa); + return 0; } -- 1.7.9.5 ------------------------------------------------------------------------------ Introducing AppDynamics Lite, a free troubleshooting tool for Java/.NET Get 100% visibility into your production application - at no cost. Code-level diagnostics for performance bottlenecks with <2% overhead Download for free and get started troubleshooting in minutes. http://p.sf.net/sfu/appdyn_d2d_ap1 _______________________________________________ Openipmi-developer mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/openipmi-developer
