aboutsummaryrefslogtreecommitdiff
path: root/hw/acpi
diff options
context:
space:
mode:
authorCorey Minyard <cminyard@mvista.com>2016-06-10 04:15:42 -0500
committerMichael S. Tsirkin <mst@redhat.com>2016-06-24 05:13:57 +0300
commit86e91dd713414dda40bb16aabe2f1fc9ba95a3a7 (patch)
treea4d03ce0a965701c3e4b6d65531127fe906502df /hw/acpi
parent35658f6e0c3dacfdb22198ee3917c0c28914d81d (diff)
acpi: Add IPMI table entries
Use the ACPI table construction tools to create an ACPI entry for IPMI. This adds a function called build_acpi_ipmi_devices to add an DSDT entry for IPMI if IPMI is compiled in and an IPMI device exists. It also adds a dummy function if IPMI is not compiled in. This conforms to section "C3-2 Locating IPMI System Interfaces in ACPI Name Space" in the IPMI 2.0 specification. Signed-off-by: Corey Minyard <cminyard@mvista.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Diffstat (limited to 'hw/acpi')
-rw-r--r--hw/acpi/Makefile.objs1
-rw-r--r--hw/acpi/ipmi.c105
2 files changed, 106 insertions, 0 deletions
diff --git a/hw/acpi/Makefile.objs b/hw/acpi/Makefile.objs
index 66bd72702b..1a48f61676 100644
--- a/hw/acpi/Makefile.objs
+++ b/hw/acpi/Makefile.objs
@@ -6,3 +6,4 @@ obj-$(CONFIG_ACPI_NVDIMM) += nvdimm.o
common-obj-$(CONFIG_ACPI) += acpi_interface.o
common-obj-$(CONFIG_ACPI) += bios-linker-loader.o
common-obj-$(CONFIG_ACPI) += aml-build.o
+common-obj-$(call land,$(CONFIG_ACPI),$(CONFIG_IPMI)) += ipmi.o
diff --git a/hw/acpi/ipmi.c b/hw/acpi/ipmi.c
new file mode 100644
index 0000000000..7e74ce4460
--- /dev/null
+++ b/hw/acpi/ipmi.c
@@ -0,0 +1,105 @@
+/*
+ * IPMI ACPI firmware handling
+ *
+ * Copyright (c) 2015,2016 Corey Minyard, MontaVista Software, LLC
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/ipmi/ipmi.h"
+#include "hw/acpi/aml-build.h"
+#include "hw/acpi/acpi.h"
+#include "hw/acpi/ipmi.h"
+
+static Aml *aml_ipmi_crs(IPMIFwInfo *info)
+{
+ Aml *crs = aml_resource_template();
+
+ /*
+ * The base address is fixed and cannot change. That may be different
+ * if someone does PCI, but we aren't there yet.
+ */
+ switch (info->memspace) {
+ case IPMI_MEMSPACE_IO:
+ aml_append(crs, aml_io(AML_DECODE16, info->base_address,
+ info->base_address + info->register_length - 1,
+ info->register_spacing, info->register_length));
+ break;
+ case IPMI_MEMSPACE_MEM32:
+ aml_append(crs,
+ aml_dword_memory(AML_POS_DECODE,
+ AML_MIN_FIXED, AML_MAX_FIXED,
+ AML_NON_CACHEABLE, AML_READ_WRITE,
+ 0xffffffff,
+ info->base_address,
+ info->base_address + info->register_length - 1,
+ info->register_spacing, info->register_length));
+ break;
+ case IPMI_MEMSPACE_MEM64:
+ aml_append(crs,
+ aml_qword_memory(AML_POS_DECODE,
+ AML_MIN_FIXED, AML_MAX_FIXED,
+ AML_NON_CACHEABLE, AML_READ_WRITE,
+ 0xffffffffffffffffULL,
+ info->base_address,
+ info->base_address + info->register_length - 1,
+ info->register_spacing, info->register_length));
+ break;
+ case IPMI_MEMSPACE_SMBUS:
+ aml_append(crs, aml_return(aml_int(info->base_address)));
+ break;
+ default:
+ abort();
+ }
+
+ if (info->interrupt_number) {
+ aml_append(crs, aml_irq_no_flags(info->interrupt_number));
+ }
+
+ return crs;
+}
+
+static Aml *aml_ipmi_device(IPMIFwInfo *info)
+{
+ Aml *dev;
+ uint16_t version = ((info->ipmi_spec_major_revision << 8)
+ | (info->ipmi_spec_minor_revision << 4));
+
+ assert(info->ipmi_spec_minor_revision <= 15);
+
+ dev = aml_device("MI%d", info->uuid);
+ aml_append(dev, aml_name_decl("_HID", aml_eisaid("IPI0001")));
+ aml_append(dev, aml_name_decl("_STR", aml_string("ipmi_%s",
+ info->interface_name)));
+ aml_append(dev, aml_name_decl("_UID", aml_int(info->uuid)));
+ aml_append(dev, aml_name_decl("_CRS", aml_ipmi_crs(info)));
+ aml_append(dev, aml_name_decl("_IFT", aml_int(info->interface_type)));
+ aml_append(dev, aml_name_decl("_SRV", aml_int(version)));
+
+ return dev;
+}
+
+void build_acpi_ipmi_devices(Aml *scope, BusState *bus)
+{
+
+ BusChild *kid;
+
+ QTAILQ_FOREACH(kid, &bus->children, sibling) {
+ IPMIInterface *ii;
+ IPMIInterfaceClass *iic;
+ IPMIFwInfo info;
+ Object *obj = object_dynamic_cast(OBJECT(kid->child),
+ TYPE_IPMI_INTERFACE);
+
+ if (!obj) {
+ continue;
+ }
+
+ ii = IPMI_INTERFACE(obj);
+ iic = IPMI_INTERFACE_GET_CLASS(obj);
+ iic->get_fwinfo(ii, &info);
+ aml_append(scope, aml_ipmi_device(&info));
+ }
+}