X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/133fe77437d3a23bf1fd70a231b4f29d5fa0571c..fba72476c6b7be60ac74c5bcdc06c61242d1fe4f:/hw/isa/lpc_ich9.c diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c index 51ce12dad6..bd655b8405 100644 --- a/hw/isa/lpc_ich9.c +++ b/hw/isa/lpc_ich9.c @@ -7,7 +7,7 @@ * VA Linux Systems Japan K.K. * Copyright (C) 2012 Jason Baron * - * This is based on piix_pci.c, but heavily modified. + * This is based on piix.c, but heavily modified. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -357,14 +357,13 @@ static void ich9_set_sci(void *opaque, int irq_num, int level) } } -void ich9_lpc_pm_init(PCIDevice *lpc_pci) +void ich9_lpc_pm_init(PCIDevice *lpc_pci, bool smm_enabled) { ICH9LPCState *lpc = ICH9_LPC_DEVICE(lpc_pci); - qemu_irq *sci_irq; - - sci_irq = qemu_allocate_irqs(ich9_set_sci, lpc, 1); - ich9_pm_init(lpc_pci, &lpc->pm, sci_irq[0]); + qemu_irq sci_irq; + sci_irq = qemu_allocate_irq(ich9_set_sci, lpc, 0); + ich9_pm_init(lpc_pci, &lpc->pm, smm_enabled, sci_irq); ich9_lpc_reset(&lpc->d.qdev); } @@ -378,6 +377,9 @@ static void ich9_apm_ctrl_changed(uint32_t val, void *arg) acpi_pm1_cnt_update(&lpc->pm.acpi_regs, val == ICH9_APM_ACPI_ENABLE, val == ICH9_APM_ACPI_DISABLE); + if (val == ICH9_APM_ACPI_ENABLE || val == ICH9_APM_ACPI_DISABLE) { + return; + } /* SMI_EN = PMBASE + 30. SMI control and enable register */ if (lpc->pm.smi_en & ICH9_PMIO_SMI_EN_APMC_EN) { @@ -410,12 +412,28 @@ static void ich9_lpc_rcba_update(ICH9LPCState *lpc, uint32_t rbca_old) } } +/* config:GEN_PMCON* */ +static void +ich9_lpc_pmcon_update(ICH9LPCState *lpc) +{ + uint16_t gen_pmcon_1 = pci_get_word(lpc->d.config + ICH9_LPC_GEN_PMCON_1); + uint16_t wmask; + + if (gen_pmcon_1 & ICH9_LPC_GEN_PMCON_1_SMI_LOCK) { + wmask = pci_get_word(lpc->d.wmask + ICH9_LPC_GEN_PMCON_1); + wmask &= ~ICH9_LPC_GEN_PMCON_1_SMI_LOCK; + pci_set_word(lpc->d.wmask + ICH9_LPC_GEN_PMCON_1, wmask); + lpc->pm.smi_en_wmask &= ~1; + } +} + static int ich9_lpc_post_load(void *opaque, int version_id) { ICH9LPCState *lpc = opaque; ich9_lpc_pmbase_update(lpc); ich9_lpc_rcba_update(lpc, 0 /* disabled ICH9_LPC_RBCA_EN */); + ich9_lpc_pmcon_update(lpc); return 0; } @@ -438,6 +456,9 @@ static void ich9_lpc_config_write(PCIDevice *d, if (ranges_overlap(addr, len, ICH9_LPC_PIRQE_ROUT, 4)) { pci_bus_fire_intx_routing_notifier(lpc->d.bus); } + if (ranges_overlap(addr, len, ICH9_LPC_GEN_PMCON_1, 8)) { + ich9_lpc_pmcon_update(lpc); + } } static void ich9_lpc_reset(DeviceState *qdev) @@ -494,7 +515,7 @@ static void ich9_lpc_machine_ready(Notifier *n, void *opaque) /* lpt */ pci_conf[0x82] |= 0x04; } - if (memory_region_present(io_as, 0x3f0)) { + if (memory_region_present(io_as, 0x3f2)) { /* floppy */ pci_conf[0x82] |= 0x08; } @@ -563,12 +584,19 @@ static void ich9_lpc_add_properties(ICH9LPCState *lpc) ich9_pm_add_properties(OBJECT(lpc), &lpc->pm, NULL); } -static int ich9_lpc_initfn(PCIDevice *d) +static void ich9_lpc_initfn(Object *obj) +{ + ICH9LPCState *lpc = ICH9_LPC_DEVICE(obj); + + ich9_lpc_add_properties(lpc); +} + +static int ich9_lpc_init(PCIDevice *d) { ICH9LPCState *lpc = ICH9_LPC_DEVICE(d); ISABus *isa_bus; - isa_bus = isa_bus_new(&d->qdev, get_system_io()); + isa_bus = isa_bus_new(DEVICE(d), get_system_memory(), get_system_io()); pci_set_long(d->wmask + ICH9_LPC_PMBASE, ICH9_LPC_PMBASE_BASE_ADDRESS_MASK); @@ -589,10 +617,31 @@ static int ich9_lpc_initfn(PCIDevice *d) memory_region_add_subregion_overlap(pci_address_space_io(d), ICH9_RST_CNT_IOPORT, &lpc->rst_cnt_mem, 1); + return 0; +} - ich9_lpc_add_properties(lpc); +static void ich9_device_plug_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev); - return 0; + ich9_pm_device_plug_cb(&lpc->pm, dev, errp); +} + +static void ich9_device_unplug_request_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev); + + ich9_pm_device_unplug_request_cb(&lpc->pm, dev, errp); +} + +static void ich9_device_unplug_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev); + + ich9_pm_device_unplug_cb(&lpc->pm, dev, errp); } static bool ich9_rst_cnt_needed(void *opaque) @@ -606,6 +655,7 @@ static const VMStateDescription vmstate_ich9_rst_cnt = { .name = "ICH9LPC/rst_cnt", .version_id = 1, .minimum_version_id = 1, + .needed = ich9_rst_cnt_needed, .fields = (VMStateField[]) { VMSTATE_UINT8(rst_cnt, ICH9LPCState), VMSTATE_END_OF_LIST() @@ -616,7 +666,6 @@ static const VMStateDescription vmstate_ich9_lpc = { .name = "ICH9LPC", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .post_load = ich9_lpc_post_load, .fields = (VMStateField[]) { VMSTATE_PCI_DEVICE(d, ICH9LPCState), @@ -626,12 +675,9 @@ static const VMStateDescription vmstate_ich9_lpc = { VMSTATE_UINT32(sci_level, ICH9LPCState), VMSTATE_END_OF_LIST() }, - .subsections = (VMStateSubsection[]) { - { - .vmsd = &vmstate_ich9_rst_cnt, - .needed = ich9_rst_cnt_needed - }, - { 0 } + .subsections = (const VMStateDescription*[]) { + &vmstate_ich9_rst_cnt, + NULL } }; @@ -639,10 +685,12 @@ static void ich9_lpc_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); + AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_CLASS(klass); set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->reset = ich9_lpc_reset; - k->init = ich9_lpc_initfn; + k->init = ich9_lpc_init; dc->vmsd = &vmstate_ich9_lpc; k->config_write = ich9_lpc_config_write; dc->desc = "ICH9 LPC bridge"; @@ -655,13 +703,23 @@ static void ich9_lpc_class_init(ObjectClass *klass, void *data) * pc_q35_init() */ dc->cannot_instantiate_with_device_add_yet = true; + hc->plug = ich9_device_plug_cb; + hc->unplug_request = ich9_device_unplug_request_cb; + hc->unplug = ich9_device_unplug_cb; + adevc->ospm_status = ich9_pm_ospm_status; } static const TypeInfo ich9_lpc_info = { .name = TYPE_ICH9_LPC_DEVICE, .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(struct ICH9LPCState), + .instance_init = ich9_lpc_initfn, .class_init = ich9_lpc_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_HOTPLUG_HANDLER }, + { TYPE_ACPI_DEVICE_IF }, + { } + } }; static void ich9_lpc_register(void)