1 /* 2 * QEMU PCI IPMI KCS 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_kcs.h" 28 #include "hw/pci/pci.h" 29 #include "qom/object.h" 30 31 #define TYPE_PCI_IPMI_KCS "pci-ipmi-kcs" 32 typedef struct PCIIPMIKCSDevice PCIIPMIKCSDevice; 33 DECLARE_INSTANCE_CHECKER(PCIIPMIKCSDevice, PCI_IPMI_KCS, 34 TYPE_PCI_IPMI_KCS) 35 36 struct PCIIPMIKCSDevice { 37 PCIDevice dev; 38 IPMIKCS kcs; 39 bool irq_enabled; 40 uint32_t uuid; 41 }; 42 43 static void pci_ipmi_raise_irq(IPMIKCS *ik) 44 { 45 PCIIPMIKCSDevice *pik = ik->opaque; 46 47 pci_set_irq(&pik->dev, true); 48 } 49 50 static void pci_ipmi_lower_irq(IPMIKCS *ik) 51 { 52 PCIIPMIKCSDevice *pik = ik->opaque; 53 54 pci_set_irq(&pik->dev, false); 55 } 56 57 static void pci_ipmi_kcs_realize(PCIDevice *pd, Error **errp) 58 { 59 Error *err = NULL; 60 PCIIPMIKCSDevice *pik = PCI_IPMI_KCS(pd); 61 IPMIInterface *ii = IPMI_INTERFACE(pd); 62 IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii); 63 64 if (!pik->kcs.bmc) { 65 error_setg(errp, "IPMI device requires a bmc attribute to be set"); 66 return; 67 } 68 69 pik->uuid = ipmi_next_uuid(); 70 71 pik->kcs.bmc->intf = ii; 72 pik->kcs.opaque = pik; 73 74 pci_config_set_prog_interface(pd->config, 0x01); /* KCS */ 75 pci_config_set_interrupt_pin(pd->config, 0x01); 76 pik->kcs.use_irq = 1; 77 pik->kcs.raise_irq = pci_ipmi_raise_irq; 78 pik->kcs.lower_irq = pci_ipmi_lower_irq; 79 80 iic->init(ii, 8, &err); 81 if (err) { 82 error_propagate(errp, err); 83 return; 84 } 85 pci_register_bar(pd, 0, PCI_BASE_ADDRESS_SPACE_IO, &pik->kcs.io); 86 } 87 88 const VMStateDescription vmstate_PCIIPMIKCSDevice = { 89 .name = TYPE_IPMI_INTERFACE_PREFIX "pci-kcs", 90 .version_id = 1, 91 .minimum_version_id = 1, 92 .fields = (VMStateField[]) { 93 VMSTATE_PCI_DEVICE(dev, PCIIPMIKCSDevice), 94 VMSTATE_STRUCT(kcs, PCIIPMIKCSDevice, 1, vmstate_IPMIKCS, IPMIKCS), 95 VMSTATE_END_OF_LIST() 96 } 97 }; 98 99 static void pci_ipmi_kcs_instance_init(Object *obj) 100 { 101 PCIIPMIKCSDevice *pik = PCI_IPMI_KCS(obj); 102 103 ipmi_bmc_find_and_link(obj, (Object **) &pik->kcs.bmc); 104 } 105 106 static void *pci_ipmi_kcs_get_backend_data(IPMIInterface *ii) 107 { 108 PCIIPMIKCSDevice *pik = PCI_IPMI_KCS(ii); 109 110 return &pik->kcs; 111 } 112 113 static void pci_ipmi_kcs_class_init(ObjectClass *oc, void *data) 114 { 115 DeviceClass *dc = DEVICE_CLASS(oc); 116 PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc); 117 IPMIInterfaceClass *iic = IPMI_INTERFACE_CLASS(oc); 118 119 pdc->vendor_id = PCI_VENDOR_ID_QEMU; 120 pdc->device_id = PCI_DEVICE_ID_QEMU_IPMI; 121 pdc->revision = 1; 122 pdc->class_id = PCI_CLASS_SERIAL_IPMI; 123 124 dc->vmsd = &vmstate_PCIIPMIKCSDevice; 125 dc->desc = "PCI IPMI KCS"; 126 pdc->realize = pci_ipmi_kcs_realize; 127 128 iic->get_backend_data = pci_ipmi_kcs_get_backend_data; 129 ipmi_kcs_class_init(iic); 130 } 131 132 static const TypeInfo pci_ipmi_kcs_info = { 133 .name = TYPE_PCI_IPMI_KCS, 134 .parent = TYPE_PCI_DEVICE, 135 .instance_size = sizeof(PCIIPMIKCSDevice), 136 .instance_init = pci_ipmi_kcs_instance_init, 137 .class_init = pci_ipmi_kcs_class_init, 138 .interfaces = (InterfaceInfo[]) { 139 { TYPE_IPMI_INTERFACE }, 140 { INTERFACE_CONVENTIONAL_PCI_DEVICE }, 141 { } 142 } 143 }; 144 145 static void pci_ipmi_kcs_register_types(void) 146 { 147 type_register_static(&pci_ipmi_kcs_info); 148 } 149 150 type_init(pci_ipmi_kcs_register_types) 151