1 /* 2 * QEMU PCI IPMI BT emulation 3 * 4 * Copyright (c) 2017 Corey Minyard, MontaVista Software, LLC 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 * THE SOFTWARE. 23 */ 24 #include "qemu/osdep.h" 25 #include "migration/vmstate.h" 26 #include "qapi/error.h" 27 #include "hw/ipmi/ipmi_bt.h" 28 #include "hw/pci/pci_device.h" 29 #include "qom/object.h" 30 31 #define TYPE_PCI_IPMI_BT "pci-ipmi-bt" 32 OBJECT_DECLARE_SIMPLE_TYPE(PCIIPMIBTDevice, PCI_IPMI_BT) 33 34 struct PCIIPMIBTDevice { 35 PCIDevice dev; 36 IPMIBT bt; 37 bool irq_enabled; 38 uint32_t uuid; 39 }; 40 41 static void pci_ipmi_bt_get_fwinfo(struct IPMIInterface *ii, IPMIFwInfo *info) 42 { 43 PCIIPMIBTDevice *pib = PCI_IPMI_BT(ii); 44 45 ipmi_bt_get_fwinfo(&pib->bt, info); 46 info->irq_source = IPMI_PCI_IRQ; 47 info->interrupt_number = pci_intx(&pib->dev); 48 info->i2c_slave_address = pib->bt.bmc->slave_addr; 49 info->uuid = pib->uuid; 50 } 51 52 static void pci_ipmi_raise_irq(IPMIBT *ib) 53 { 54 PCIIPMIBTDevice *pib = ib->opaque; 55 56 pci_set_irq(&pib->dev, true); 57 } 58 59 static void pci_ipmi_lower_irq(IPMIBT *ib) 60 { 61 PCIIPMIBTDevice *pib = ib->opaque; 62 63 pci_set_irq(&pib->dev, false); 64 } 65 66 static void pci_ipmi_bt_realize(PCIDevice *pd, Error **errp) 67 { 68 Error *err = NULL; 69 PCIIPMIBTDevice *pib = PCI_IPMI_BT(pd); 70 IPMIInterface *ii = IPMI_INTERFACE(pd); 71 IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii); 72 73 if (!pib->bt.bmc) { 74 error_setg(errp, "IPMI device requires a bmc attribute to be set"); 75 return; 76 } 77 78 pib->uuid = ipmi_next_uuid(); 79 80 pib->bt.bmc->intf = ii; 81 pib->bt.opaque = pib; 82 83 pci_config_set_prog_interface(pd->config, 0x02); /* BT */ 84 pci_config_set_interrupt_pin(pd->config, 0x01); 85 pib->bt.use_irq = 1; 86 pib->bt.raise_irq = pci_ipmi_raise_irq; 87 pib->bt.lower_irq = pci_ipmi_lower_irq; 88 89 iic->init(ii, 8, &err); 90 if (err) { 91 error_propagate(errp, err); 92 return; 93 } 94 pci_register_bar(pd, 0, PCI_BASE_ADDRESS_SPACE_IO, &pib->bt.io); 95 } 96 97 const VMStateDescription vmstate_PCIIPMIBTDevice = { 98 .name = TYPE_IPMI_INTERFACE_PREFIX "pci-bt", 99 .version_id = 1, 100 .minimum_version_id = 1, 101 .fields = (const VMStateField[]) { 102 VMSTATE_PCI_DEVICE(dev, PCIIPMIBTDevice), 103 VMSTATE_STRUCT(bt, PCIIPMIBTDevice, 1, vmstate_IPMIBT, IPMIBT), 104 VMSTATE_END_OF_LIST() 105 } 106 }; 107 108 static void pci_ipmi_bt_instance_init(Object *obj) 109 { 110 PCIIPMIBTDevice *pib = PCI_IPMI_BT(obj); 111 112 ipmi_bmc_find_and_link(obj, (Object **) &pib->bt.bmc); 113 } 114 115 static void *pci_ipmi_bt_get_backend_data(IPMIInterface *ii) 116 { 117 PCIIPMIBTDevice *pib = PCI_IPMI_BT(ii); 118 119 return &pib->bt; 120 } 121 122 static void pci_ipmi_bt_class_init(ObjectClass *oc, void *data) 123 { 124 DeviceClass *dc = DEVICE_CLASS(oc); 125 PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc); 126 IPMIInterfaceClass *iic = IPMI_INTERFACE_CLASS(oc); 127 128 pdc->vendor_id = PCI_VENDOR_ID_QEMU; 129 pdc->device_id = PCI_DEVICE_ID_QEMU_IPMI; 130 pdc->revision = 1; 131 pdc->class_id = PCI_CLASS_SERIAL_IPMI; 132 133 dc->vmsd = &vmstate_PCIIPMIBTDevice; 134 dc->desc = "PCI IPMI BT"; 135 pdc->realize = pci_ipmi_bt_realize; 136 137 iic->get_backend_data = pci_ipmi_bt_get_backend_data; 138 ipmi_bt_class_init(iic); 139 iic->get_fwinfo = pci_ipmi_bt_get_fwinfo; 140 } 141 142 static const TypeInfo pci_ipmi_bt_info = { 143 .name = TYPE_PCI_IPMI_BT, 144 .parent = TYPE_PCI_DEVICE, 145 .instance_size = sizeof(PCIIPMIBTDevice), 146 .instance_init = pci_ipmi_bt_instance_init, 147 .class_init = pci_ipmi_bt_class_init, 148 .interfaces = (InterfaceInfo[]) { 149 { TYPE_IPMI_INTERFACE }, 150 { INTERFACE_CONVENTIONAL_PCI_DEVICE }, 151 { } 152 } 153 }; 154 155 static void pci_ipmi_bt_register_types(void) 156 { 157 type_register_static(&pci_ipmi_bt_info); 158 } 159 160 type_init(pci_ipmi_bt_register_types) 161