@@ -50,6 +50,7 @@ void cpu_hotplug_hw_init(MemoryRegion *as, Object *owner,
typedef struct CPUHotplugFeatures {
bool acpi_1_compatible;
bool has_legacy_cphp;
+ const char *smi_path;
} CPUHotplugFeatures;
void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
@@ -14,6 +14,8 @@
#define ACPI_CPU_CMD_DATA_OFFSET_RW 8
#define ACPI_CPU_CMD_DATA2_OFFSET_R 0
+#define OVMF_CPUHP_SMI_CMD 4
+
enum {
CPHP_GET_NEXT_CPU_WITH_EVENT_CMD = 0,
CPHP_OST_EVENT_CMD = 1,
@@ -473,6 +475,10 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
Aml *next_cpu_cmd = aml_int(CPHP_GET_NEXT_CPU_WITH_EVENT_CMD);
aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
+ if (opts.smi_path) {
+ aml_append(method, aml_store(aml_int(OVMF_CPUHP_SMI_CMD),
+ aml_name("%s", opts.smi_path)));
+ }
aml_append(method, aml_store(one, has_event));
while_ctx = aml_while(aml_equal(has_event, one));
{
@@ -95,6 +95,7 @@ typedef struct AcpiPmInfo {
bool s3_disabled;
bool s4_disabled;
bool pcihp_bridge_en;
+ bool smi_on_cpuhp;
uint8_t s4_val;
AcpiFadtData fadt;
uint16_t cpu_hp_io_base;
@@ -194,6 +195,7 @@ static void acpi_get_pm_info(MachineState *machine, AcpiPmInfo *pm)
pm->cpu_hp_io_base = 0;
pm->pcihp_io_base = 0;
pm->pcihp_io_len = 0;
+ pm->smi_on_cpuhp = false;
assert(obj);
init_common_fadt_data(machine, obj, &pm->fadt);
@@ -213,6 +215,9 @@ static void acpi_get_pm_info(MachineState *machine, AcpiPmInfo *pm)
pm->fadt.reset_val = 0xf;
pm->fadt.flags |= 1 << ACPI_FADT_F_RESET_REG_SUP;
pm->cpu_hp_io_base = ICH9_CPU_HOTPLUG_IO_BASE;
+ pm->smi_on_cpuhp =
+ !!(object_property_get_uint(lpc, "x-smi-negotiated-features", NULL)
+ & BIT_ULL(ICH9_LPC_SMI_F_CPU_HOTPLUG_BIT));
}
/* The above need not be conditional on machine type because the reset port
@@ -1515,6 +1520,31 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
aml_append(dev, aml_name_decl("_UID", aml_int(1)));
aml_append(dev, build_q35_osc_method());
aml_append(sb_scope, dev);
+
+ if (pm->smi_on_cpuhp) {
+ /* reserve SMI block resources */
+ dev = aml_device("PCI0.SMI0");
+ aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A06")));
+ aml_append(dev, aml_name_decl("_UID", aml_string("SMI resources")));
+ crs = aml_resource_template();
+ aml_append(crs,
+ aml_io(
+ AML_DECODE16,
+ ACPI_PORT_SMI_CMD,
+ ACPI_PORT_SMI_CMD,
+ 1,
+ 1)
+ );
+ aml_append(dev, aml_name_decl("_CRS", crs));
+ aml_append(dev, aml_operation_region("SMIR", AML_SYSTEM_IO,
+ aml_int(0xB2), 1));
+ field = aml_field("SMIR", AML_BYTE_ACC, AML_NOLOCK,
+ AML_WRITE_AS_ZEROS);
+ aml_append(field, aml_named_field("SMIC", 8));
+ aml_append(dev, field);
+ aml_append(sb_scope, dev);
+ }
+
aml_append(dsdt, sb_scope);
build_hpet_aml(dsdt);
@@ -1530,7 +1560,8 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
build_legacy_cpu_hotplug_aml(dsdt, machine, pm->cpu_hp_io_base);
} else {
CPUHotplugFeatures opts = {
- .acpi_1_compatible = true, .has_legacy_cphp = true
+ .acpi_1_compatible = true, .has_legacy_cphp = true,
+ .smi_path = pm->smi_on_cpuhp ? "\\_SB.PCI0.SMI0.SMIC" : NULL,
};
build_cpus_aml(dsdt, machine, opts, pm->cpu_hp_io_base,
"\\_SB.PCI0", "\\_GPE._E02");
@@ -643,6 +643,9 @@ static void ich9_lpc_initfn(Object *obj)
&acpi_enable_cmd, OBJ_PROP_FLAG_READ);
object_property_add_uint8_ptr(OBJECT(lpc), ACPI_PM_PROP_ACPI_DISABLE_CMD,
&acpi_disable_cmd, OBJ_PROP_FLAG_READ);
+ object_property_add_uint64_ptr(obj, "x-smi-negotiated-features",
+ &lpc->smi_negotiated_features,
+ OBJ_PROP_FLAG_READ);
ich9_pm_add_properties(obj, &lpc->pm);
}
In case firmware has negotiated CPU hotplug SMI feature, generate AML to describe SMI IO port region and send SMI to firmware on each CPU hotplug SCI. It might be not really usable, but should serve as a starting point to discuss how better to deal with split hotplug sequence during hot-add ( ex scenario where it will break is: hot-add -> (QEMU) add CPU in hotplug regs -> (QEMU) SCI -1-> (OS) scan -1-> (OS) SMI -1-> (FW) pull in CPU1 *** -1-> (OS) start iterating hotplug regs hot-add -> (QEMU) add CPU in hotplug regs -> (QEMU) SCI -2-> (OS) scan (blocked on mutex till previous scan is finished) -1-> (OS) 1st added CPU1 send device check event -> INIT/SIPI -1-> (OS) 1st added CPU2 send device check event -> INIT/SIPI that's where it explodes, since FW didn't see CPU2 when SMI was called ) hot remove will throw in yet another set of problems, so lets discuss both here and see if we can really share hotplug registers block between FW and AML or we should do something else with it. Signed-off-by: Igor Mammedov <imammedo@redhat.com> --- v0: - s/aml_string/aml_eisaid/ /fixes Windows BSOD, on nonsense value/ (Laszlo Ersek <lersek@redhat.com>) - put SMI device under PCI0 like the rest of hotplug IO port - do not generate SMI AML if CPU hotplug SMI feature hasn't been negotiated --- include/hw/acpi/cpu.h | 1 + hw/acpi/cpu.c | 6 ++++++ hw/i386/acpi-build.c | 33 ++++++++++++++++++++++++++++++++- hw/isa/lpc_ich9.c | 3 +++ 4 files changed, 42 insertions(+), 1 deletion(-)