Second ping https://patchew.org/QEMU/1e4d59a49e7f2e02cf522e799a7bf5f3fa3fba1f.1722414006.git....@dprinz.de/ https://lore.kernel.org/qemu-devel/1e4d59a49e7f2e02cf522e799a7bf5f3fa3fba1f.1722414006.git....@dprinz.de/
On Wed Aug 21, 2024 at 3:00 PM CEST, Dominic Prinz wrote: > Ping > > https://patchew.org/QEMU/1e4d59a49e7f2e02cf522e799a7bf5f3fa3fba1f.1722414006.git....@dprinz.de/ > https://lore.kernel.org/qemu-devel/1e4d59a49e7f2e02cf522e799a7bf5f3fa3fba1f.1722414006.git....@dprinz.de/ > > On Wed Jul 31, 2024 at 10:28 AM CEST, Dominic Prinz wrote: > > This patch implements the periodic and the swsmi ICH9 chipset timer. They > > are > > especially useful when prototyping UEFI firmware (e.g. with EDK2's OVMF) > > using QEMU. > > > > For backwards compatibility, the compat properties "x-smi-swsmi-timer", > > and "x-smi-periodic-timer" are introduced. > > > > Additionally, writes to the SMI_STS register are enabled for the > > corresponding two bits. > > > > Signed-off-by: Dominic Prinz <g...@dprinz.de> > > --- > > Changes since previous version: > > - Ensured backwards compatablity by introducing two compat properties > > - Introduced write mask for SMI_STS register to make future work easier > > > > hw/acpi/ich9.c | 23 +++++++++ > > hw/acpi/ich9_timer.c | 93 +++++++++++++++++++++++++++++++++++ > > hw/acpi/meson.build | 2 +- > > hw/i386/pc.c | 2 + > > hw/isa/lpc_ich9.c | 14 ++++++ > > include/hw/acpi/ich9.h | 6 +++ > > include/hw/acpi/ich9_timer.h | 23 +++++++++ > > include/hw/southbridge/ich9.h | 4 ++ > > 8 files changed, 166 insertions(+), 1 deletion(-) > > create mode 100644 hw/acpi/ich9_timer.c > > create mode 100644 include/hw/acpi/ich9_timer.h > > > > diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c > > index 02d8546bd3..c15e5b8281 100644 > > --- a/hw/acpi/ich9.c > > +++ b/hw/acpi/ich9.c > > @@ -35,6 +35,7 @@ > > #include "sysemu/runstate.h" > > #include "hw/acpi/acpi.h" > > #include "hw/acpi/ich9_tco.h" > > +#include "hw/acpi/ich9_timer.h" > > > > #include "hw/southbridge/ich9.h" > > #include "hw/mem/pc-dimm.h" > > @@ -108,6 +109,18 @@ static void ich9_smi_writel(void *opaque, hwaddr addr, > > uint64_t val, > > } > > pm->smi_en &= ~pm->smi_en_wmask; > > pm->smi_en |= (val & pm->smi_en_wmask); > > + if (pm->swsmi_timer_enabled) { > > + ich9_pm_update_swsmi_timer(pm, pm->smi_en & > > + ICH9_PMIO_SMI_EN_SWSMI_EN); > > + } > > + if (pm->periodic_timer_enabled) { > > + ich9_pm_update_periodic_timer(pm, pm->smi_en & > > + > > ICH9_PMIO_SMI_EN_PERIODIC_EN); > > + } > > + break; > > + case 4: > > + pm->smi_sts &= ~pm->smi_sts_wmask; > > + pm->smi_sts |= (val & pm->smi_sts_wmask); > > break; > > } > > } > > @@ -286,6 +299,8 @@ static void pm_powerdown_req(Notifier *n, void *opaque) > > > > void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, qemu_irq sci_irq) > > { > > + pm->smi_sts_wmask = 0; > > + > > memory_region_init(&pm->io, OBJECT(lpc_pci), "ich9-pm", > > ICH9_PMIO_SIZE); > > memory_region_set_enabled(&pm->io, false); > > memory_region_add_subregion(pci_address_space_io(lpc_pci), > > @@ -305,6 +320,14 @@ void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs > > *pm, qemu_irq sci_irq) > > "acpi-smi", 8); > > memory_region_add_subregion(&pm->io, ICH9_PMIO_SMI_EN, &pm->io_smi); > > > > + if (pm->swsmi_timer_enabled) { > > + ich9_pm_swsmi_timer_init(pm); > > + } > > + > > + if (pm->periodic_timer_enabled) { > > + ich9_pm_periodic_timer_init(pm); > > + } > > + > > if (pm->enable_tco) { > > acpi_pm_tco_init(&pm->tco_regs, &pm->io); > > } > > diff --git a/hw/acpi/ich9_timer.c b/hw/acpi/ich9_timer.c > > new file mode 100644 > > index 0000000000..5b1c910156 > > --- /dev/null > > +++ b/hw/acpi/ich9_timer.c > > @@ -0,0 +1,93 @@ > > +/* > > + * QEMU ICH9 Timer emulation > > + * > > + * Copyright (c) 2024 Dominic Prinz <g...@dprinz.de> > > + * > > + * This work is licensed under the terms of the GNU GPL, version 2 or > > later. > > + * See the COPYING file in the top-level directory. > > + */ > > + > > +#include "qemu/osdep.h" > > +#include "hw/core/cpu.h" > > +#include "hw/pci/pci.h" > > +#include "hw/southbridge/ich9.h" > > +#include "qemu/timer.h" > > + > > +#include "hw/acpi/ich9_timer.h" > > + > > +void ich9_pm_update_swsmi_timer(ICH9LPCPMRegs *pm, bool enable) > > +{ > > + uint16_t swsmi_rate_sel; > > + int64_t expire_time; > > + ICH9LPCState *lpc; > > + > > + if (enable) { > > + lpc = container_of(pm, ICH9LPCState, pm); > > + swsmi_rate_sel = > > + (pci_get_word(lpc->d.config + ICH9_LPC_GEN_PMCON_3) & 0xc0) >> > > 6; > > + > > + if (swsmi_rate_sel == 0) { > > + expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + > > 1500000LL; > > + } else { > > + expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + > > + 8 * (1 << swsmi_rate_sel) * 1000000LL; > > + } > > + > > + timer_mod(pm->swsmi_timer, expire_time); > > + } else { > > + timer_del(pm->swsmi_timer); > > + } > > +} > > + > > +static void ich9_pm_swsmi_timer_expired(void *opaque) > > +{ > > + ICH9LPCPMRegs *pm = opaque; > > + > > + pm->smi_sts |= ICH9_PMIO_SMI_STS_SWSMI_STS; > > + ich9_generate_smi(); > > + > > + ich9_pm_update_swsmi_timer(pm, pm->smi_en & ICH9_PMIO_SMI_EN_SWSMI_EN); > > +} > > + > > +void ich9_pm_swsmi_timer_init(ICH9LPCPMRegs *pm) > > +{ > > + pm->smi_sts_wmask |= ICH9_PMIO_SMI_STS_SWSMI_STS; > > + pm->swsmi_timer = > > + timer_new_ns(QEMU_CLOCK_VIRTUAL, ich9_pm_swsmi_timer_expired, pm); > > +} > > + > > +void ich9_pm_update_periodic_timer(ICH9LPCPMRegs *pm, bool enable) > > +{ > > + uint16_t per_smi_sel; > > + int64_t expire_time; > > + ICH9LPCState *lpc; > > + > > + if (enable) { > > + lpc = container_of(pm, ICH9LPCState, pm); > > + per_smi_sel = pci_get_word(lpc->d.config + ICH9_LPC_GEN_PMCON_1) & > > 3; > > + expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + > > + 8 * (1 << (3 - per_smi_sel)) * > > NANOSECONDS_PER_SECOND; > > + > > + timer_mod(pm->periodic_timer, expire_time); > > + } else { > > + timer_del(pm->periodic_timer); > > + } > > +} > > + > > +static void ich9_pm_periodic_timer_expired(void *opaque) > > +{ > > + ICH9LPCPMRegs *pm = opaque; > > + > > + pm->smi_sts = ICH9_PMIO_SMI_STS_PERIODIC_STS; > > + ich9_generate_smi(); > > + > > + ich9_pm_update_periodic_timer(pm, > > + pm->smi_en & > > ICH9_PMIO_SMI_EN_PERIODIC_EN); > > +} > > + > > +void ich9_pm_periodic_timer_init(ICH9LPCPMRegs *pm) > > +{ > > + pm->smi_sts_wmask |= ICH9_PMIO_SMI_STS_PERIODIC_STS; > > + pm->periodic_timer = > > + timer_new_ns(QEMU_CLOCK_VIRTUAL, ich9_pm_periodic_timer_expired, > > pm); > > +} > > diff --git a/hw/acpi/meson.build b/hw/acpi/meson.build > > index fa5c07db90..7f8ccc9b7a 100644 > > --- a/hw/acpi/meson.build > > +++ b/hw/acpi/meson.build > > @@ -24,7 +24,7 @@ acpi_ss.add(when: 'CONFIG_ACPI_PCI_BRIDGE', if_true: > > files('pci-bridge.c')) > > acpi_ss.add(when: 'CONFIG_ACPI_PCIHP', if_true: files('pcihp.c')) > > acpi_ss.add(when: 'CONFIG_ACPI_PCIHP', if_false: > > files('acpi-pci-hotplug-stub.c')) > > acpi_ss.add(when: 'CONFIG_ACPI_VIOT', if_true: files('viot.c')) > > -acpi_ss.add(when: 'CONFIG_ACPI_ICH9', if_true: files('ich9.c', > > 'ich9_tco.c')) > > +acpi_ss.add(when: 'CONFIG_ACPI_ICH9', if_true: files('ich9.c', > > 'ich9_tco.c', 'ich9_timer.c')) > > acpi_ss.add(when: 'CONFIG_ACPI_ERST', if_true: files('erst.c')) > > acpi_ss.add(when: 'CONFIG_IPMI', if_true: files('ipmi.c'), if_false: > > files('ipmi-stub.c')) > > acpi_ss.add(when: 'CONFIG_PC', if_false: files('acpi-x86-stub.c')) > > diff --git a/hw/i386/pc.c b/hw/i386/pc.c > > index c74931d577..a97b1b1f57 100644 > > --- a/hw/i386/pc.c > > +++ b/hw/i386/pc.c > > @@ -85,6 +85,8 @@ GlobalProperty pc_compat_9_0[] = { > > { TYPE_X86_CPU, "guest-phys-bits", "0" }, > > { "sev-guest", "legacy-vm-type", "on" }, > > { TYPE_X86_CPU, "legacy-multi-node", "on" }, > > + { "ICH9-LPC", "x-smi-swsmi-timer", "off" }, > > + { "ICH9-LPC", "x-smi-periodic-timer", "off" }, > > }; > > const size_t pc_compat_9_0_len = G_N_ELEMENTS(pc_compat_9_0); > > > > diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c > > index bd727b2320..ab17b76f54 100644 > > --- a/hw/isa/lpc_ich9.c > > +++ b/hw/isa/lpc_ich9.c > > @@ -43,6 +43,7 @@ > > #include "hw/southbridge/ich9.h" > > #include "hw/acpi/acpi.h" > > #include "hw/acpi/ich9.h" > > +#include "hw/acpi/ich9_timer.h" > > #include "hw/pci/pci_bus.h" > > #include "hw/qdev-properties.h" > > #include "sysemu/runstate.h" > > @@ -531,6 +532,15 @@ 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 (lpc->pm.swsmi_timer_enabled) { > > + ich9_pm_update_swsmi_timer( > > + &lpc->pm, lpc->pm.smi_en & ICH9_PMIO_SMI_EN_SWSMI_EN); > > + } > > + if (lpc->pm.periodic_timer_enabled) { > > + ich9_pm_update_periodic_timer( > > + &lpc->pm, lpc->pm.smi_en & ICH9_PMIO_SMI_EN_PERIODIC_EN); > > + } > > + > > 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; > > @@ -826,6 +836,10 @@ static Property ich9_lpc_properties[] = { > > ICH9_LPC_SMI_F_CPU_HOTPLUG_BIT, true), > > DEFINE_PROP_BIT64("x-smi-cpu-hotunplug", ICH9LPCState, > > smi_host_features, > > ICH9_LPC_SMI_F_CPU_HOT_UNPLUG_BIT, true), > > + DEFINE_PROP_BOOL("x-smi-swsmi-timer", ICH9LPCState, > > + pm.swsmi_timer_enabled, true), > > + DEFINE_PROP_BOOL("x-smi-periodic-timer", ICH9LPCState, > > + pm.periodic_timer_enabled, true), > > DEFINE_PROP_END_OF_LIST(), > > }; > > > > diff --git a/include/hw/acpi/ich9.h b/include/hw/acpi/ich9.h > > index 2faf7f0cae..245fe08dc2 100644 > > --- a/include/hw/acpi/ich9.h > > +++ b/include/hw/acpi/ich9.h > > @@ -46,6 +46,7 @@ typedef struct ICH9LPCPMRegs { > > uint32_t smi_en; > > uint32_t smi_en_wmask; > > uint32_t smi_sts; > > + uint32_t smi_sts_wmask; > > > > qemu_irq irq; /* SCI */ > > > > @@ -68,6 +69,11 @@ typedef struct ICH9LPCPMRegs { > > bool smm_compat; > > bool enable_tco; > > TCOIORegs tco_regs; > > + > > + bool swsmi_timer_enabled; > > + bool periodic_timer_enabled; > > + QEMUTimer *swsmi_timer; > > + QEMUTimer *periodic_timer; > > } ICH9LPCPMRegs; > > > > #define ACPI_PM_PROP_TCO_ENABLED "enable_tco" > > diff --git a/include/hw/acpi/ich9_timer.h b/include/hw/acpi/ich9_timer.h > > new file mode 100644 > > index 0000000000..5112df4385 > > --- /dev/null > > +++ b/include/hw/acpi/ich9_timer.h > > @@ -0,0 +1,23 @@ > > +/* > > + * QEMU ICH9 Timer emulation > > + * > > + * Copyright (c) 2024 Dominic Prinz <g...@dprinz.de> > > + * > > + * This work is licensed under the terms of the GNU GPL, version 2 or > > later. > > + * See the COPYING file in the top-level directory. > > + */ > > + > > +#ifndef HW_ACPI_ICH9_TIMER_H > > +#define HW_ACPI_ICH9_TIMER_H > > + > > +#include "hw/acpi/ich9.h" > > + > > +void ich9_pm_update_swsmi_timer(ICH9LPCPMRegs *pm, bool enable); > > + > > +void ich9_pm_swsmi_timer_init(ICH9LPCPMRegs *pm); > > + > > +void ich9_pm_update_periodic_timer(ICH9LPCPMRegs *pm, bool enable); > > + > > +void ich9_pm_periodic_timer_init(ICH9LPCPMRegs *pm); > > + > > +#endif > > diff --git a/include/hw/southbridge/ich9.h b/include/hw/southbridge/ich9.h > > index fd01649d04..6c60017024 100644 > > --- a/include/hw/southbridge/ich9.h > > +++ b/include/hw/southbridge/ich9.h > > @@ -196,8 +196,12 @@ struct ICH9LPCState { > > #define ICH9_PMIO_GPE0_LEN 16 > > #define ICH9_PMIO_SMI_EN 0x30 > > #define ICH9_PMIO_SMI_EN_APMC_EN (1 << 5) > > +#define ICH9_PMIO_SMI_EN_SWSMI_EN (1 << 6) > > #define ICH9_PMIO_SMI_EN_TCO_EN (1 << 13) > > +#define ICH9_PMIO_SMI_EN_PERIODIC_EN (1 << 14) > > #define ICH9_PMIO_SMI_STS 0x34 > > +#define ICH9_PMIO_SMI_STS_SWSMI_STS (1 << 6) > > +#define ICH9_PMIO_SMI_STS_PERIODIC_STS (1 << 14) > > #define ICH9_PMIO_TCO_RLD 0x60 > > #define ICH9_PMIO_TCO_LEN 32 > > > > -- > > 2.34.1