186e91dd7SCorey Minyard /* 286e91dd7SCorey Minyard * IPMI ACPI firmware handling 386e91dd7SCorey Minyard * 486e91dd7SCorey Minyard * Copyright (c) 2015,2016 Corey Minyard, MontaVista Software, LLC 586e91dd7SCorey Minyard * 686e91dd7SCorey Minyard * This work is licensed under the terms of the GNU GPL, version 2 or later. 786e91dd7SCorey Minyard * See the COPYING file in the top-level directory. 886e91dd7SCorey Minyard */ 986e91dd7SCorey Minyard 1086e91dd7SCorey Minyard #include "qemu/osdep.h" 1186e91dd7SCorey Minyard #include "hw/ipmi/ipmi.h" 1286e91dd7SCorey Minyard #include "hw/acpi/aml-build.h" 1386e91dd7SCorey Minyard #include "hw/acpi/acpi.h" 1486e91dd7SCorey Minyard #include "hw/acpi/ipmi.h" 1586e91dd7SCorey Minyard 16*576d05b6SCorey Minyard static Aml *aml_ipmi_crs(IPMIFwInfo *info, const char *resource) 1786e91dd7SCorey Minyard { 1886e91dd7SCorey Minyard Aml *crs = aml_resource_template(); 1986e91dd7SCorey Minyard 2086e91dd7SCorey Minyard /* 2186e91dd7SCorey Minyard * The base address is fixed and cannot change. That may be different 2286e91dd7SCorey Minyard * if someone does PCI, but we aren't there yet. 2386e91dd7SCorey Minyard */ 2486e91dd7SCorey Minyard switch (info->memspace) { 2586e91dd7SCorey Minyard case IPMI_MEMSPACE_IO: 2686e91dd7SCorey Minyard aml_append(crs, aml_io(AML_DECODE16, info->base_address, 2786e91dd7SCorey Minyard info->base_address + info->register_length - 1, 2886e91dd7SCorey Minyard info->register_spacing, info->register_length)); 2986e91dd7SCorey Minyard break; 3086e91dd7SCorey Minyard case IPMI_MEMSPACE_MEM32: 3186e91dd7SCorey Minyard aml_append(crs, 3286e91dd7SCorey Minyard aml_dword_memory(AML_POS_DECODE, 3386e91dd7SCorey Minyard AML_MIN_FIXED, AML_MAX_FIXED, 3486e91dd7SCorey Minyard AML_NON_CACHEABLE, AML_READ_WRITE, 3586e91dd7SCorey Minyard 0xffffffff, 3686e91dd7SCorey Minyard info->base_address, 3786e91dd7SCorey Minyard info->base_address + info->register_length - 1, 3886e91dd7SCorey Minyard info->register_spacing, info->register_length)); 3986e91dd7SCorey Minyard break; 4086e91dd7SCorey Minyard case IPMI_MEMSPACE_MEM64: 4186e91dd7SCorey Minyard aml_append(crs, 4286e91dd7SCorey Minyard aml_qword_memory(AML_POS_DECODE, 4386e91dd7SCorey Minyard AML_MIN_FIXED, AML_MAX_FIXED, 4486e91dd7SCorey Minyard AML_NON_CACHEABLE, AML_READ_WRITE, 4586e91dd7SCorey Minyard 0xffffffffffffffffULL, 4686e91dd7SCorey Minyard info->base_address, 4786e91dd7SCorey Minyard info->base_address + info->register_length - 1, 4886e91dd7SCorey Minyard info->register_spacing, info->register_length)); 4986e91dd7SCorey Minyard break; 5086e91dd7SCorey Minyard case IPMI_MEMSPACE_SMBUS: 51*576d05b6SCorey Minyard aml_append(crs, aml_i2c_serial_bus_device(info->base_address, 52*576d05b6SCorey Minyard resource)); 5386e91dd7SCorey Minyard break; 5486e91dd7SCorey Minyard default: 5586e91dd7SCorey Minyard abort(); 5686e91dd7SCorey Minyard } 5786e91dd7SCorey Minyard 5886e91dd7SCorey Minyard if (info->interrupt_number) { 5986e91dd7SCorey Minyard aml_append(crs, aml_irq_no_flags(info->interrupt_number)); 6086e91dd7SCorey Minyard } 6186e91dd7SCorey Minyard 6286e91dd7SCorey Minyard return crs; 6386e91dd7SCorey Minyard } 6486e91dd7SCorey Minyard 65*576d05b6SCorey Minyard static Aml *aml_ipmi_device(IPMIFwInfo *info, const char *resource) 6686e91dd7SCorey Minyard { 6786e91dd7SCorey Minyard Aml *dev; 6886e91dd7SCorey Minyard uint16_t version = ((info->ipmi_spec_major_revision << 8) 6986e91dd7SCorey Minyard | (info->ipmi_spec_minor_revision << 4)); 7086e91dd7SCorey Minyard 7186e91dd7SCorey Minyard assert(info->ipmi_spec_minor_revision <= 15); 7286e91dd7SCorey Minyard 7386e91dd7SCorey Minyard dev = aml_device("MI%d", info->uuid); 7486e91dd7SCorey Minyard aml_append(dev, aml_name_decl("_HID", aml_eisaid("IPI0001"))); 7586e91dd7SCorey Minyard aml_append(dev, aml_name_decl("_STR", aml_string("ipmi_%s", 7686e91dd7SCorey Minyard info->interface_name))); 7786e91dd7SCorey Minyard aml_append(dev, aml_name_decl("_UID", aml_int(info->uuid))); 78*576d05b6SCorey Minyard aml_append(dev, aml_name_decl("_CRS", aml_ipmi_crs(info, resource))); 7986e91dd7SCorey Minyard aml_append(dev, aml_name_decl("_IFT", aml_int(info->interface_type))); 8086e91dd7SCorey Minyard aml_append(dev, aml_name_decl("_SRV", aml_int(version))); 8186e91dd7SCorey Minyard 8286e91dd7SCorey Minyard return dev; 8386e91dd7SCorey Minyard } 8486e91dd7SCorey Minyard 85*576d05b6SCorey Minyard void build_acpi_ipmi_devices(Aml *scope, BusState *bus, const char *resource) 8686e91dd7SCorey Minyard { 8786e91dd7SCorey Minyard 8886e91dd7SCorey Minyard BusChild *kid; 8986e91dd7SCorey Minyard 9086e91dd7SCorey Minyard QTAILQ_FOREACH(kid, &bus->children, sibling) { 9186e91dd7SCorey Minyard IPMIInterface *ii; 9286e91dd7SCorey Minyard IPMIInterfaceClass *iic; 9386e91dd7SCorey Minyard IPMIFwInfo info; 9486e91dd7SCorey Minyard Object *obj = object_dynamic_cast(OBJECT(kid->child), 9586e91dd7SCorey Minyard TYPE_IPMI_INTERFACE); 9686e91dd7SCorey Minyard 9786e91dd7SCorey Minyard if (!obj) { 9886e91dd7SCorey Minyard continue; 9986e91dd7SCorey Minyard } 10086e91dd7SCorey Minyard 10186e91dd7SCorey Minyard ii = IPMI_INTERFACE(obj); 10286e91dd7SCorey Minyard iic = IPMI_INTERFACE_GET_CLASS(obj); 103698ae42bSCorey Minyard memset(&info, 0, sizeof(info)); 10486e91dd7SCorey Minyard iic->get_fwinfo(ii, &info); 105*576d05b6SCorey Minyard aml_append(scope, aml_ipmi_device(&info, resource)); 10686e91dd7SCorey Minyard } 10786e91dd7SCorey Minyard } 108