smbios_type_38.c (3153B)
1/* 2 * IPMI SMBIOS firmware handling 3 * 4 * Copyright (c) 2015,2016 Corey Minyard, MontaVista Software, LLC 5 * 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. 8 */ 9 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" 15 16/* SMBIOS type 38 - IPMI */ 17struct 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; 26} QEMU_PACKED; 27 28static void smbios_build_one_type_38(IPMIFwInfo *info) 29{ 30 uint64_t baseaddr = info->base_address; 31 SMBIOS_BUILD_TABLE_PRE(38, 0x3000, true); 32 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; 38 39 assert(info->ipmi_spec_minor_revision <= 15); 40 assert(info->ipmi_spec_major_revision <= 15); 41 42 /* or 1 to set it to I/O space */ 43 switch (info->memspace) { 44 case IPMI_MEMSPACE_IO: 45 baseaddr |= 1; 46 break; 47 case IPMI_MEMSPACE_MEM32: 48 case IPMI_MEMSPACE_MEM64: 49 break; 50 case IPMI_MEMSPACE_SMBUS: 51 baseaddr <<= 1; 52 break; 53 } 54 55 t->base_address = cpu_to_le64(baseaddr); 56 57 t->base_address_modifier = 0; 58 if (info->irq_type == IPMI_LEVEL_IRQ) { 59 t->base_address_modifier |= 1; 60 } 61 switch (info->register_spacing) { 62 case 1: 63 break; 64 case 4: 65 t->base_address_modifier |= 1 << 6; 66 break; 67 case 16: 68 t->base_address_modifier |= 2 << 6; 69 break; 70 default: 71 error_report("IPMI register spacing %d is not compatible with" 72 " SMBIOS, ignoring this entry.", info->register_spacing); 73 return; 74 } 75 t->interrupt_number = info->interrupt_number; 76 77 SMBIOS_BUILD_TABLE_POST; 78} 79 80static void smbios_add_ipmi_devices(BusState *bus) 81{ 82 BusChild *kid; 83 84 QTAILQ_FOREACH(kid, &bus->children, sibling) { 85 DeviceState *dev = kid->child; 86 Object *obj = object_dynamic_cast(OBJECT(dev), TYPE_IPMI_INTERFACE); 87 BusState *childbus; 88 89 if (obj) { 90 IPMIInterface *ii; 91 IPMIInterfaceClass *iic; 92 IPMIFwInfo info; 93 94 ii = IPMI_INTERFACE(obj); 95 iic = IPMI_INTERFACE_GET_CLASS(obj); 96 memset(&info, 0, sizeof(info)); 97 if (!iic->get_fwinfo) { 98 continue; 99 } 100 iic->get_fwinfo(ii, &info); 101 smbios_build_one_type_38(&info); 102 continue; 103 } 104 105 QLIST_FOREACH(childbus, &dev->child_bus, sibling) { 106 smbios_add_ipmi_devices(childbus); 107 } 108 } 109} 110 111void smbios_build_type_38_table(void) 112{ 113 BusState *bus; 114 115 bus = sysbus_get_default(); 116 if (bus) { 117 smbios_add_ipmi_devices(bus); 118 } 119}