2 * IPMI SMBIOS firmware handling
4 * Copyright (c) 2015,2016 Corey Minyard, MontaVista Software, LLC
6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
7 * See the COPYING file in the top-level directory.
10 #include "qemu/osdep.h"
11 #include "hw/ipmi/ipmi.h"
12 #include "hw/firmware/smbios.h"
13 #include "qemu/error-report.h"
14 #include "smbios_build.h"
16 /* SMBIOS type 38 - IPMI */
17 struct smbios_type_38
{
18 struct smbios_structure_header header
;
19 uint8_t interface_type
;
20 uint8_t ipmi_spec_revision
;
21 uint8_t i2c_slave_address
;
22 uint8_t nv_storage_device_address
;
23 uint64_t base_address
;
24 uint8_t base_address_modifier
;
25 uint8_t interrupt_number
;
28 static void smbios_build_one_type_38(IPMIFwInfo
*info
)
30 uint64_t baseaddr
= info
->base_address
;
31 SMBIOS_BUILD_TABLE_PRE(38, 0x3000, true);
33 t
->interface_type
= info
->interface_type
;
34 t
->ipmi_spec_revision
= ((info
->ipmi_spec_major_revision
<< 4)
35 | info
->ipmi_spec_minor_revision
);
36 t
->i2c_slave_address
= info
->i2c_slave_address
;
37 t
->nv_storage_device_address
= 0;
39 assert(info
->ipmi_spec_minor_revision
<= 15);
40 assert(info
->ipmi_spec_major_revision
<= 15);
42 /* or 1 to set it to I/O space */
43 switch (info
->memspace
) {
44 case IPMI_MEMSPACE_IO
:
47 case IPMI_MEMSPACE_MEM32
:
48 case IPMI_MEMSPACE_MEM64
:
50 case IPMI_MEMSPACE_SMBUS
:
55 t
->base_address
= cpu_to_le64(baseaddr
);
57 t
->base_address_modifier
= 0;
58 if (info
->irq_type
== IPMI_LEVEL_IRQ
) {
59 t
->base_address_modifier
|= 1;
61 switch (info
->register_spacing
) {
65 t
->base_address_modifier
|= 1 << 6;
68 t
->base_address_modifier
|= 2 << 6;
71 error_report("IPMI register spacing %d is not compatible with"
72 " SMBIOS, ignoring this entry.", info
->register_spacing
);
75 t
->interrupt_number
= info
->interrupt_number
;
77 SMBIOS_BUILD_TABLE_POST
;
80 static void smbios_add_ipmi_devices(BusState
*bus
)
84 QTAILQ_FOREACH(kid
, &bus
->children
, sibling
) {
85 DeviceState
*dev
= kid
->child
;
86 Object
*obj
= object_dynamic_cast(OBJECT(dev
), TYPE_IPMI_INTERFACE
);
91 IPMIInterfaceClass
*iic
;
94 ii
= IPMI_INTERFACE(obj
);
95 iic
= IPMI_INTERFACE_GET_CLASS(obj
);
96 memset(&info
, 0, sizeof(info
));
97 if (!iic
->get_fwinfo
) {
100 iic
->get_fwinfo(ii
, &info
);
101 smbios_build_one_type_38(&info
);
105 QLIST_FOREACH(childbus
, &dev
->child_bus
, sibling
) {
106 smbios_add_ipmi_devices(childbus
);
111 void smbios_build_type_38_table(void)
115 bus
= sysbus_get_default();
117 smbios_add_ipmi_devices(bus
);