10719029cSCorey Minyard /* 20719029cSCorey Minyard * QEMU ISA IPMI KCS emulation 30719029cSCorey Minyard * 40f310cd6SCorey Minyard * Copyright (c) 2015,2017 Corey Minyard, MontaVista Software, LLC 50719029cSCorey Minyard * 60719029cSCorey Minyard * Permission is hereby granted, free of charge, to any person obtaining a copy 70719029cSCorey Minyard * of this software and associated documentation files (the "Software"), to deal 80719029cSCorey Minyard * in the Software without restriction, including without limitation the rights 90719029cSCorey Minyard * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 100719029cSCorey Minyard * copies of the Software, and to permit persons to whom the Software is 110719029cSCorey Minyard * furnished to do so, subject to the following conditions: 120719029cSCorey Minyard * 130719029cSCorey Minyard * The above copyright notice and this permission notice shall be included in 140719029cSCorey Minyard * all copies or substantial portions of the Software. 150719029cSCorey Minyard * 160719029cSCorey Minyard * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 170719029cSCorey Minyard * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 180719029cSCorey Minyard * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 190719029cSCorey Minyard * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 200719029cSCorey Minyard * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 210719029cSCorey Minyard * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 220719029cSCorey Minyard * THE SOFTWARE. 230719029cSCorey Minyard */ 240b8fa32fSMarkus Armbruster 250430891cSPeter Maydell #include "qemu/osdep.h" 260b8fa32fSMarkus Armbruster #include "qemu/module.h" 27da34e65cSMarkus Armbruster #include "qapi/error.h" 2864552b6bSMarkus Armbruster #include "hw/irq.h" 290f310cd6SCorey Minyard #include "hw/ipmi/ipmi_kcs.h" 300719029cSCorey Minyard #include "hw/isa/isa.h" 31a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h" 32d6454270SMarkus Armbruster #include "migration/vmstate.h" 33db1015e9SEduardo Habkost #include "qom/object.h" 345876d9b5SIgor Mammedov #include "hw/acpi/ipmi.h" 350719029cSCorey Minyard 360719029cSCorey Minyard #define TYPE_ISA_IPMI_KCS "isa-ipmi-kcs" 378063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(ISAIPMIKCSDevice, ISA_IPMI_KCS) 380719029cSCorey Minyard 39db1015e9SEduardo Habkost struct ISAIPMIKCSDevice { 400719029cSCorey Minyard ISADevice dev; 41f4014512SPeter Maydell int32_t isairq; 420f310cd6SCorey Minyard qemu_irq irq; 430719029cSCorey Minyard IPMIKCS kcs; 4415139b8eSCorey Minyard uint32_t uuid; 45db1015e9SEduardo Habkost }; 460719029cSCorey Minyard 470f310cd6SCorey Minyard static void isa_ipmi_kcs_get_fwinfo(IPMIInterface *ii, IPMIFwInfo *info) 4815139b8eSCorey Minyard { 4915139b8eSCorey Minyard ISAIPMIKCSDevice *iik = ISA_IPMI_KCS(ii); 5015139b8eSCorey Minyard 510f310cd6SCorey Minyard ipmi_kcs_get_fwinfo(&iik->kcs, info); 5215139b8eSCorey Minyard info->interrupt_number = iik->isairq; 5315139b8eSCorey Minyard info->uuid = iik->uuid; 5415139b8eSCorey Minyard } 5515139b8eSCorey Minyard 560f310cd6SCorey Minyard static void isa_ipmi_kcs_raise_irq(IPMIKCS *ik) 5715139b8eSCorey Minyard { 580f310cd6SCorey Minyard ISAIPMIKCSDevice *iik = ik->opaque; 590f310cd6SCorey Minyard 600f310cd6SCorey Minyard qemu_irq_raise(iik->irq); 610f310cd6SCorey Minyard } 620f310cd6SCorey Minyard 630f310cd6SCorey Minyard static void isa_ipmi_kcs_lower_irq(IPMIKCS *ik) 640f310cd6SCorey Minyard { 650f310cd6SCorey Minyard ISAIPMIKCSDevice *iik = ik->opaque; 660f310cd6SCorey Minyard 670f310cd6SCorey Minyard qemu_irq_lower(iik->irq); 6815139b8eSCorey Minyard } 6915139b8eSCorey Minyard 706436db5aSThomas Huth static bool vmstate_kcs_before_version2(void *opaque, int version) 716436db5aSThomas Huth { 726436db5aSThomas Huth return version <= 1; 736436db5aSThomas Huth } 746436db5aSThomas Huth 756436db5aSThomas Huth static const VMStateDescription vmstate_ISAIPMIKCSDevice = { 766436db5aSThomas Huth .name = TYPE_IPMI_INTERFACE, 776436db5aSThomas Huth .version_id = 2, 786436db5aSThomas Huth .minimum_version_id = 1, 79*09c6ac6dSRichard Henderson .fields = (const VMStateField[]) { 806436db5aSThomas Huth VMSTATE_VSTRUCT_TEST(kcs, ISAIPMIKCSDevice, vmstate_kcs_before_version2, 816436db5aSThomas Huth 0, vmstate_IPMIKCS, IPMIKCS, 1), 826436db5aSThomas Huth VMSTATE_VSTRUCT_V(kcs, ISAIPMIKCSDevice, 2, vmstate_IPMIKCS, 836436db5aSThomas Huth IPMIKCS, 2), 846436db5aSThomas Huth VMSTATE_END_OF_LIST() 856436db5aSThomas Huth } 866436db5aSThomas Huth }; 876436db5aSThomas Huth 880719029cSCorey Minyard static void ipmi_isa_realize(DeviceState *dev, Error **errp) 890719029cSCorey Minyard { 90f6166a4dSMarkus Armbruster Error *err = NULL; 910719029cSCorey Minyard ISADevice *isadev = ISA_DEVICE(dev); 920719029cSCorey Minyard ISAIPMIKCSDevice *iik = ISA_IPMI_KCS(dev); 930719029cSCorey Minyard IPMIInterface *ii = IPMI_INTERFACE(dev); 940719029cSCorey Minyard IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii); 950719029cSCorey Minyard 960719029cSCorey Minyard if (!iik->kcs.bmc) { 970719029cSCorey Minyard error_setg(errp, "IPMI device requires a bmc attribute to be set"); 980719029cSCorey Minyard return; 990719029cSCorey Minyard } 1000719029cSCorey Minyard 10115139b8eSCorey Minyard iik->uuid = ipmi_next_uuid(); 10215139b8eSCorey Minyard 1030719029cSCorey Minyard iik->kcs.bmc->intf = ii; 1040f310cd6SCorey Minyard iik->kcs.opaque = iik; 1050719029cSCorey Minyard 106f6166a4dSMarkus Armbruster iic->init(ii, 0, &err); 107f6166a4dSMarkus Armbruster if (err) { 108f6166a4dSMarkus Armbruster error_propagate(errp, err); 1090719029cSCorey Minyard return; 110f6166a4dSMarkus Armbruster } 1110719029cSCorey Minyard 1120719029cSCorey Minyard if (iik->isairq > 0) { 113215caca6SBernhard Beschow iik->irq = isa_get_irq(isadev, iik->isairq); 1140719029cSCorey Minyard iik->kcs.use_irq = 1; 1150f310cd6SCorey Minyard iik->kcs.raise_irq = isa_ipmi_kcs_raise_irq; 1160f310cd6SCorey Minyard iik->kcs.lower_irq = isa_ipmi_kcs_lower_irq; 1170719029cSCorey Minyard } 1180719029cSCorey Minyard 1190719029cSCorey Minyard qdev_set_legacy_instance_id(dev, iik->kcs.io_base, iik->kcs.io_length); 1200719029cSCorey Minyard 1210719029cSCorey Minyard isa_register_ioport(isadev, &iik->kcs.io, iik->kcs.io_base); 122bd66bcfcSCorey Minyard 1237e57b82eSCorey Minyard /* 1247e57b82eSCorey Minyard * Version 1 had an incorrect name, it clashed with the BT 1257e57b82eSCorey Minyard * IPMI device, so receive it, but transmit a different 1267e57b82eSCorey Minyard * version. 1277e57b82eSCorey Minyard */ 128bd66bcfcSCorey Minyard vmstate_register(NULL, 0, &vmstate_ISAIPMIKCSDevice, iik); 1290719029cSCorey Minyard } 1300719029cSCorey Minyard 1316436db5aSThomas Huth static void isa_ipmi_kcs_init(Object *obj) 1326436db5aSThomas Huth { 1336436db5aSThomas Huth ISAIPMIKCSDevice *iik = ISA_IPMI_KCS(obj); 1346436db5aSThomas Huth 1356436db5aSThomas Huth ipmi_bmc_find_and_link(obj, (Object **) &iik->kcs.bmc); 1366436db5aSThomas Huth } 1376436db5aSThomas Huth 1380719029cSCorey Minyard static void *isa_ipmi_kcs_get_backend_data(IPMIInterface *ii) 1390719029cSCorey Minyard { 1400719029cSCorey Minyard ISAIPMIKCSDevice *iik = ISA_IPMI_KCS(ii); 1410719029cSCorey Minyard 1420719029cSCorey Minyard return &iik->kcs; 1430719029cSCorey Minyard } 1440719029cSCorey Minyard 1450719029cSCorey Minyard static Property ipmi_isa_properties[] = { 1460719029cSCorey Minyard DEFINE_PROP_UINT32("ioport", ISAIPMIKCSDevice, kcs.io_base, 0xca2), 1470719029cSCorey Minyard DEFINE_PROP_INT32("irq", ISAIPMIKCSDevice, isairq, 5), 1480719029cSCorey Minyard DEFINE_PROP_END_OF_LIST(), 1490719029cSCorey Minyard }; 1500719029cSCorey Minyard 1510719029cSCorey Minyard static void isa_ipmi_kcs_class_init(ObjectClass *oc, void *data) 1520719029cSCorey Minyard { 1530719029cSCorey Minyard DeviceClass *dc = DEVICE_CLASS(oc); 1540719029cSCorey Minyard IPMIInterfaceClass *iic = IPMI_INTERFACE_CLASS(oc); 1555876d9b5SIgor Mammedov AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(oc); 1560719029cSCorey Minyard 1570719029cSCorey Minyard dc->realize = ipmi_isa_realize; 1584f67d30bSMarc-André Lureau device_class_set_props(dc, ipmi_isa_properties); 1590719029cSCorey Minyard 1600719029cSCorey Minyard iic->get_backend_data = isa_ipmi_kcs_get_backend_data; 1610719029cSCorey Minyard ipmi_kcs_class_init(iic); 1620f310cd6SCorey Minyard iic->get_fwinfo = isa_ipmi_kcs_get_fwinfo; 1635876d9b5SIgor Mammedov adevc->build_dev_aml = build_ipmi_dev_aml; 1640719029cSCorey Minyard } 1650719029cSCorey Minyard 1660719029cSCorey Minyard static const TypeInfo isa_ipmi_kcs_info = { 1670719029cSCorey Minyard .name = TYPE_ISA_IPMI_KCS, 1680719029cSCorey Minyard .parent = TYPE_ISA_DEVICE, 1690719029cSCorey Minyard .instance_size = sizeof(ISAIPMIKCSDevice), 1700719029cSCorey Minyard .instance_init = isa_ipmi_kcs_init, 1710719029cSCorey Minyard .class_init = isa_ipmi_kcs_class_init, 1720719029cSCorey Minyard .interfaces = (InterfaceInfo[]) { 1730719029cSCorey Minyard { TYPE_IPMI_INTERFACE }, 1745876d9b5SIgor Mammedov { TYPE_ACPI_DEV_AML_IF }, 1750719029cSCorey Minyard { } 1760719029cSCorey Minyard } 1770719029cSCorey Minyard }; 1780719029cSCorey Minyard 1790719029cSCorey Minyard static void ipmi_register_types(void) 1800719029cSCorey Minyard { 1810719029cSCorey Minyard type_register_static(&isa_ipmi_kcs_info); 1820719029cSCorey Minyard } 1830719029cSCorey Minyard 1840719029cSCorey Minyard type_init(ipmi_register_types) 185