112f983c6SCorey Minyard /*
212f983c6SCorey Minyard * QEMU PCI IPMI BT emulation
312f983c6SCorey Minyard *
412f983c6SCorey Minyard * Copyright (c) 2017 Corey Minyard, MontaVista Software, LLC
512f983c6SCorey Minyard *
612f983c6SCorey Minyard * Permission is hereby granted, free of charge, to any person obtaining a copy
712f983c6SCorey Minyard * of this software and associated documentation files (the "Software"), to deal
812f983c6SCorey Minyard * in the Software without restriction, including without limitation the rights
912f983c6SCorey Minyard * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1012f983c6SCorey Minyard * copies of the Software, and to permit persons to whom the Software is
1112f983c6SCorey Minyard * furnished to do so, subject to the following conditions:
1212f983c6SCorey Minyard *
1312f983c6SCorey Minyard * The above copyright notice and this permission notice shall be included in
1412f983c6SCorey Minyard * all copies or substantial portions of the Software.
1512f983c6SCorey Minyard *
1612f983c6SCorey Minyard * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1712f983c6SCorey Minyard * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1812f983c6SCorey Minyard * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1912f983c6SCorey Minyard * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2012f983c6SCorey Minyard * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2112f983c6SCorey Minyard * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2212f983c6SCorey Minyard * THE SOFTWARE.
2312f983c6SCorey Minyard */
2412f983c6SCorey Minyard #include "qemu/osdep.h"
2512f983c6SCorey Minyard #include "migration/vmstate.h"
2612f983c6SCorey Minyard #include "qapi/error.h"
2712f983c6SCorey Minyard #include "hw/ipmi/ipmi_bt.h"
28edf5ca5dSMarkus Armbruster #include "hw/pci/pci_device.h"
29db1015e9SEduardo Habkost #include "qom/object.h"
3012f983c6SCorey Minyard
3112f983c6SCorey Minyard #define TYPE_PCI_IPMI_BT "pci-ipmi-bt"
328063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(PCIIPMIBTDevice, PCI_IPMI_BT)
3312f983c6SCorey Minyard
34db1015e9SEduardo Habkost struct PCIIPMIBTDevice {
3512f983c6SCorey Minyard PCIDevice dev;
3612f983c6SCorey Minyard IPMIBT bt;
3712f983c6SCorey Minyard bool irq_enabled;
3812f983c6SCorey Minyard uint32_t uuid;
39db1015e9SEduardo Habkost };
4012f983c6SCorey Minyard
pci_ipmi_raise_irq(IPMIBT * ik)4112f983c6SCorey Minyard static void pci_ipmi_raise_irq(IPMIBT *ik)
4212f983c6SCorey Minyard {
4312f983c6SCorey Minyard PCIIPMIBTDevice *pik = ik->opaque;
4412f983c6SCorey Minyard
4512f983c6SCorey Minyard pci_set_irq(&pik->dev, true);
4612f983c6SCorey Minyard }
4712f983c6SCorey Minyard
pci_ipmi_lower_irq(IPMIBT * ik)4812f983c6SCorey Minyard static void pci_ipmi_lower_irq(IPMIBT *ik)
4912f983c6SCorey Minyard {
5012f983c6SCorey Minyard PCIIPMIBTDevice *pik = ik->opaque;
5112f983c6SCorey Minyard
5212f983c6SCorey Minyard pci_set_irq(&pik->dev, false);
5312f983c6SCorey Minyard }
5412f983c6SCorey Minyard
pci_ipmi_bt_realize(PCIDevice * pd,Error ** errp)5512f983c6SCorey Minyard static void pci_ipmi_bt_realize(PCIDevice *pd, Error **errp)
5612f983c6SCorey Minyard {
57f6166a4dSMarkus Armbruster Error *err = NULL;
5812f983c6SCorey Minyard PCIIPMIBTDevice *pik = PCI_IPMI_BT(pd);
5912f983c6SCorey Minyard IPMIInterface *ii = IPMI_INTERFACE(pd);
6012f983c6SCorey Minyard IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
6112f983c6SCorey Minyard
6212f983c6SCorey Minyard if (!pik->bt.bmc) {
6312f983c6SCorey Minyard error_setg(errp, "IPMI device requires a bmc attribute to be set");
6412f983c6SCorey Minyard return;
6512f983c6SCorey Minyard }
6612f983c6SCorey Minyard
6712f983c6SCorey Minyard pik->uuid = ipmi_next_uuid();
6812f983c6SCorey Minyard
6912f983c6SCorey Minyard pik->bt.bmc->intf = ii;
7012f983c6SCorey Minyard pik->bt.opaque = pik;
7112f983c6SCorey Minyard
7212f983c6SCorey Minyard pci_config_set_prog_interface(pd->config, 0x02); /* BT */
7312f983c6SCorey Minyard pci_config_set_interrupt_pin(pd->config, 0x01);
7412f983c6SCorey Minyard pik->bt.use_irq = 1;
7512f983c6SCorey Minyard pik->bt.raise_irq = pci_ipmi_raise_irq;
7612f983c6SCorey Minyard pik->bt.lower_irq = pci_ipmi_lower_irq;
7712f983c6SCorey Minyard
78f6166a4dSMarkus Armbruster iic->init(ii, 8, &err);
79f6166a4dSMarkus Armbruster if (err) {
80f6166a4dSMarkus Armbruster error_propagate(errp, err);
8112f983c6SCorey Minyard return;
8212f983c6SCorey Minyard }
8312f983c6SCorey Minyard pci_register_bar(pd, 0, PCI_BASE_ADDRESS_SPACE_IO, &pik->bt.io);
8412f983c6SCorey Minyard }
8512f983c6SCorey Minyard
8612f983c6SCorey Minyard const VMStateDescription vmstate_PCIIPMIBTDevice = {
8712f983c6SCorey Minyard .name = TYPE_IPMI_INTERFACE_PREFIX "pci-bt",
8812f983c6SCorey Minyard .version_id = 1,
8912f983c6SCorey Minyard .minimum_version_id = 1,
90*09c6ac6dSRichard Henderson .fields = (const VMStateField[]) {
9112f983c6SCorey Minyard VMSTATE_PCI_DEVICE(dev, PCIIPMIBTDevice),
9212f983c6SCorey Minyard VMSTATE_STRUCT(bt, PCIIPMIBTDevice, 1, vmstate_IPMIBT, IPMIBT),
9312f983c6SCorey Minyard VMSTATE_END_OF_LIST()
9412f983c6SCorey Minyard }
9512f983c6SCorey Minyard };
9612f983c6SCorey Minyard
pci_ipmi_bt_instance_init(Object * obj)9712f983c6SCorey Minyard static void pci_ipmi_bt_instance_init(Object *obj)
9812f983c6SCorey Minyard {
9912f983c6SCorey Minyard PCIIPMIBTDevice *pik = PCI_IPMI_BT(obj);
10012f983c6SCorey Minyard
10112f983c6SCorey Minyard ipmi_bmc_find_and_link(obj, (Object **) &pik->bt.bmc);
10212f983c6SCorey Minyard }
10312f983c6SCorey Minyard
pci_ipmi_bt_get_backend_data(IPMIInterface * ii)10412f983c6SCorey Minyard static void *pci_ipmi_bt_get_backend_data(IPMIInterface *ii)
10512f983c6SCorey Minyard {
10612f983c6SCorey Minyard PCIIPMIBTDevice *pik = PCI_IPMI_BT(ii);
10712f983c6SCorey Minyard
10812f983c6SCorey Minyard return &pik->bt;
10912f983c6SCorey Minyard }
11012f983c6SCorey Minyard
pci_ipmi_bt_class_init(ObjectClass * oc,void * data)11112f983c6SCorey Minyard static void pci_ipmi_bt_class_init(ObjectClass *oc, void *data)
11212f983c6SCorey Minyard {
11312f983c6SCorey Minyard DeviceClass *dc = DEVICE_CLASS(oc);
11412f983c6SCorey Minyard PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc);
11512f983c6SCorey Minyard IPMIInterfaceClass *iic = IPMI_INTERFACE_CLASS(oc);
11612f983c6SCorey Minyard
11712f983c6SCorey Minyard pdc->vendor_id = PCI_VENDOR_ID_QEMU;
11812f983c6SCorey Minyard pdc->device_id = PCI_DEVICE_ID_QEMU_IPMI;
11912f983c6SCorey Minyard pdc->revision = 1;
12012f983c6SCorey Minyard pdc->class_id = PCI_CLASS_SERIAL_IPMI;
12112f983c6SCorey Minyard
12212f983c6SCorey Minyard dc->vmsd = &vmstate_PCIIPMIBTDevice;
12312f983c6SCorey Minyard dc->desc = "PCI IPMI BT";
12412f983c6SCorey Minyard pdc->realize = pci_ipmi_bt_realize;
12512f983c6SCorey Minyard
12612f983c6SCorey Minyard iic->get_backend_data = pci_ipmi_bt_get_backend_data;
12712f983c6SCorey Minyard ipmi_bt_class_init(iic);
12812f983c6SCorey Minyard }
12912f983c6SCorey Minyard
13012f983c6SCorey Minyard static const TypeInfo pci_ipmi_bt_info = {
13112f983c6SCorey Minyard .name = TYPE_PCI_IPMI_BT,
13212f983c6SCorey Minyard .parent = TYPE_PCI_DEVICE,
13312f983c6SCorey Minyard .instance_size = sizeof(PCIIPMIBTDevice),
13412f983c6SCorey Minyard .instance_init = pci_ipmi_bt_instance_init,
13512f983c6SCorey Minyard .class_init = pci_ipmi_bt_class_init,
13612f983c6SCorey Minyard .interfaces = (InterfaceInfo[]) {
13712f983c6SCorey Minyard { TYPE_IPMI_INTERFACE },
13812f983c6SCorey Minyard { INTERFACE_CONVENTIONAL_PCI_DEVICE },
13912f983c6SCorey Minyard { }
14012f983c6SCorey Minyard }
14112f983c6SCorey Minyard };
14212f983c6SCorey Minyard
pci_ipmi_bt_register_types(void)14312f983c6SCorey Minyard static void pci_ipmi_bt_register_types(void)
14412f983c6SCorey Minyard {
14512f983c6SCorey Minyard type_register_static(&pci_ipmi_bt_info);
14612f983c6SCorey Minyard }
14712f983c6SCorey Minyard
14812f983c6SCorey Minyard type_init(pci_ipmi_bt_register_types)
149