On Tue, May 17, 2016 at 04:43:16PM +0200, Igor Mammedov wrote: > Add necessary CPU hotplug methods to handle hotplug > events. > > Signed-off-by: Igor Mammedov <imamm...@redhat.com> > --- > v1: > - make replace _MAT method with named buffer object > as its content is static > --- > hw/acpi/cpu.c | 187 > +++++++++++++++++++++++++++++++++++++++++++++++++- > hw/i386/acpi-build.c | 3 +- > include/hw/acpi/cpu.h | 4 +- > 3 files changed, 190 insertions(+), 4 deletions(-) > > diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c > index b3e1cca..28d3894 100644 > --- a/hw/acpi/cpu.c > +++ b/hw/acpi/cpu.c > @@ -207,24 +207,178 @@ const VMStateDescription vmstate_cpu_hotplug = { > }; > > #define CPU_NAME_FMT "C%.03X" > - > -void build_cpus_aml(Aml *table, MachineState *machine, bool acpi1_compat) > +#define CPUHP_RES_DEVICE "PRES" > +#define CPU_LOCK "CPLK" > +#define CPU_STS_METHOD "CSTA" > +#define CPU_SCAN_METHOD "CSCN" > +#define CPU_EJECT_METHOD "CEJ0" > +#define CPU_NOTIFY_METHOD "CTFY" > + > +#define CPU_ENABLED "CPEN" > +#define CPU_SELECTOR "CSEL" > +#define CPU_EJECT_EVENT "CEJ0" > +#define CPU_INSERT_EVENT "CINS" > +#define CPU_REMOVE_EVENT "CRMV" > + > +void build_cpus_aml(Aml *table, MachineState *machine, bool acpi1_compat, > + const char *res_root, const char *event_handler_method, > + hwaddr io_base) > { > + Aml *ifctx; > + Aml *field; > + Aml *method; > + Aml *cpu_ctrl_dev; > Aml *cpus_dev; > + Aml *zero = aml_int(0); > Aml *sb_scope = aml_scope("_SB"); > MachineClass *mc = MACHINE_GET_CLASS(machine); > CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(machine); > + char *cphp_res_path = g_strdup_printf("%s." CPUHP_RES_DEVICE, res_root); > + Object *obj = object_resolve_path_type("", TYPE_ACPI_DEVICE_IF, NULL); > + AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(obj); > + AcpiDeviceIf *adev = ACPI_DEVICE_IF(obj); > + > + cpu_ctrl_dev = aml_device("%s", cphp_res_path); > + { > + Aml *crs; > + > + aml_append(cpu_ctrl_dev, > + aml_name_decl("_HID", aml_eisaid("PNP0A06"))); > + aml_append(cpu_ctrl_dev, > + aml_name_decl("_UID", aml_string("CPU Hotplug resources"))); > + aml_append(cpu_ctrl_dev, aml_mutex(CPU_LOCK, 0)); > + > + crs = aml_resource_template(); > + aml_append(crs, aml_io(AML_DECODE16, io_base, io_base, 1, > + ACPI_CPU_HOTPLUG_REG_LEN)); > + aml_append(cpu_ctrl_dev, aml_name_decl("_CRS", crs)); > + > + /* declare CPU hotplug MMIO region with related access fields */ > + aml_append(cpu_ctrl_dev, > + aml_operation_region("PRST", AML_SYSTEM_IO, aml_int(io_base), > + ACPI_CPU_HOTPLUG_REG_LEN)); > + > + field = aml_field("PRST", AML_BYTE_ACC, AML_NOLOCK, > + AML_WRITE_AS_ZEROS); > + aml_append(field, aml_reserved_field(ACPI_CPU_FLAGS_OFFSET_RW * 8)); > + /* 1 if enabled, read only */ > + aml_append(field, aml_named_field(CPU_ENABLED, 1)); > + /* (read) 1 if has a insert event. (write) 1 to clear event */ > + aml_append(field, aml_named_field(CPU_INSERT_EVENT, 1)); > + /* (read) 1 if has a remove event. (write) 1 to clear event */ > + aml_append(field, aml_named_field(CPU_REMOVE_EVENT, 1)); > + /* initiates device eject, write only */ > + aml_append(field, aml_named_field(CPU_EJECT_EVENT, 1)); > + aml_append(cpu_ctrl_dev, field); > + > + field = aml_field("PRST", AML_DWORD_ACC, AML_NOLOCK, AML_PRESERVE); > + /* CPU selector, write only */ > + aml_append(field, aml_named_field(CPU_SELECTOR, 32)); > + aml_append(cpu_ctrl_dev, field); > + > + } > + aml_append(sb_scope, cpu_ctrl_dev); > + > cpus_dev = aml_device("\\_SB.CPUS"); > { > int i; > + Aml *one = aml_int(1); > + Aml *cpu_selector = aml_name("%s.%s", cphp_res_path, CPU_SELECTOR); > + Aml *ins_evt = aml_name("%s.%s", cphp_res_path, CPU_INSERT_EVENT); > + Aml *rm_evt = aml_name("%s.%s", cphp_res_path, CPU_REMOVE_EVENT); > + Aml *ej_evt = aml_name("%s.%s", cphp_res_path, CPU_EJECT_EVENT); > + Aml *is_enabled = aml_name("%s.%s", cphp_res_path, CPU_ENABLED); > + Aml *ctrl_lock = aml_name("%s.%s", cphp_res_path, CPU_LOCK); > > aml_append(cpus_dev, aml_name_decl("_HID", aml_string("ACPI0010"))); > aml_append(cpus_dev, aml_name_decl("_CID", aml_eisaid("PNP0A05"))); > > + method = aml_method(CPU_NOTIFY_METHOD, 2, AML_NOTSERIALIZED); > + for (i = 0; i < arch_ids->len; i++) {
wow that will be a ton of acpi code. why not create an AML loop? > + Aml *cpu = aml_name(CPU_NAME_FMT, i); > + Aml *uid = aml_arg(0); > + Aml *event = aml_arg(1); > + > + ifctx = aml_if(aml_equal(uid, aml_int(i))); > + { > + aml_append(ifctx, aml_notify(cpu, event)); > + } > + aml_append(method, ifctx); > + } > + aml_append(cpus_dev, method); > + > + method = aml_method(CPU_STS_METHOD, 1, AML_SERIALIZED); > + { > + Aml *idx = aml_arg(0); > + Aml *sta = aml_local(0); > + > + aml_append(method, aml_acquire(ctrl_lock, 0xFFFF)); > + aml_append(method, aml_store(idx, cpu_selector)); > + aml_append(method, aml_store(zero, sta)); > + ifctx = aml_if(aml_equal(is_enabled, one)); > + { > + aml_append(ifctx, aml_store(aml_int(0xF), sta)); > + } > + aml_append(method, ifctx); > + aml_append(method, aml_release(ctrl_lock)); > + aml_append(method, aml_return(sta)); > + } > + aml_append(cpus_dev, method); > + > + method = aml_method(CPU_EJECT_METHOD, 1, AML_SERIALIZED); > + { > + Aml *idx = aml_arg(0); > + > + aml_append(method, aml_acquire(ctrl_lock, 0xFFFF)); > + aml_append(method, aml_store(idx, cpu_selector)); > + aml_append(method, aml_store(one, ej_evt)); > + aml_append(method, aml_release(ctrl_lock)); > + } > + aml_append(cpus_dev, method); > + > + method = aml_method(CPU_SCAN_METHOD, 0, AML_SERIALIZED); > + { > + Aml *else_ctx; > + Aml *while_ctx; > + Aml *idx = aml_local(0); > + Aml *eject_req = aml_int(3); > + Aml *dev_chk = aml_int(1); > + Aml *cpus_count = aml_int(arch_ids->len); > + > + aml_append(method, aml_acquire(ctrl_lock, 0xFFFF)); > + aml_append(method, aml_store(zero, idx)); > + while_ctx = aml_while(aml_lless(idx, cpus_count)); > + { > + aml_append(while_ctx, aml_store(idx, cpu_selector)); > + ifctx = aml_if(aml_equal(ins_evt, one)); > + { > + aml_append(ifctx, > + aml_call2(CPU_NOTIFY_METHOD, idx, dev_chk)); > + aml_append(ifctx, aml_store(one, ins_evt)); > + } > + aml_append(while_ctx, ifctx); > + else_ctx = aml_else(); > + ifctx = aml_if(aml_equal(rm_evt, one)); > + { > + aml_append(ifctx, > + aml_call2(CPU_NOTIFY_METHOD, idx, eject_req)); > + aml_append(ifctx, aml_store(one, rm_evt)); > + } > + aml_append(else_ctx, ifctx); > + aml_append(while_ctx, else_ctx); > + > + aml_append(while_ctx, aml_add(idx, one, idx)); > + } > + aml_append(method, while_ctx); > + aml_append(method, aml_release(ctrl_lock)); > + } > + aml_append(cpus_dev, method); > + > /* build Processor object for each processor */ > for (i = 0; i < arch_ids->len; i++) { > Aml *dev; > Aml *uid = aml_int(i); > + GArray *madt_buf = g_array_new(0, 1, 1); > int arch_id = arch_ids->cpus[i].arch_id; > > if (acpi1_compat && arch_id < 255) { > @@ -235,11 +389,40 @@ void build_cpus_aml(Aml *table, MachineState *machine, > bool acpi1_compat) > aml_append(dev, aml_name_decl("_UID", uid)); > } > > + method = aml_method("_STA", 0, AML_SERIALIZED); > + aml_append(method, aml_return(aml_call1(CPU_STS_METHOD, uid))); > + aml_append(dev, method); > + > + /* build _MAT object */ > + assert(adevc && adevc->madt_cpu); > + adevc->madt_cpu(adev, i, arch_ids, madt_buf); > + switch (madt_buf->data[0]) { > + case ACPI_APIC_PROCESSOR: { > + AcpiMadtProcessorApic *apic = (void *)madt_buf->data; > + apic->flags = cpu_to_le32(1); > + break; > + } > + default: > + assert(0); > + } > + aml_append(dev, aml_name_decl("_MAT", > + aml_buffer(madt_buf->len, (uint8_t *)madt_buf->data))); > + g_array_free(madt_buf, true); > + > + method = aml_method("_EJ0", 1, AML_NOTSERIALIZED); > + aml_append(method, aml_call1(CPU_EJECT_METHOD, uid)); > + aml_append(dev, method); > + > aml_append(cpus_dev, dev); > } > } > aml_append(sb_scope, cpus_dev); > aml_append(table, sb_scope); > > + method = aml_method(event_handler_method, 0, AML_NOTSERIALIZED); > + aml_append(method, aml_call0("\\_SB.CPUS." CPU_SCAN_METHOD)); > + aml_append(table, method); > + > + g_free(cphp_res_path); > g_free(arch_ids); > } > diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c > index 47d4182..c62c020 100644 > --- a/hw/i386/acpi-build.c > +++ b/hw/i386/acpi-build.c > @@ -1949,7 +1949,8 @@ build_dsdt(GArray *table_data, GArray *linker, > if (pm->legacy_cpu_hp) { > build_legacy_cpu_hotplug_aml(dsdt, machine, pm->cpu_hp_io_base); > } else { > - build_cpus_aml(dsdt, machine, true); > + build_cpus_aml(dsdt, machine, true, > + "\\_SB.PCI0", "\\_GPE._E02", pm->cpu_hp_io_base); > } > build_memory_hotplug_aml(dsdt, nr_mem, pm->mem_hp_io_base, > pm->mem_hp_io_len); > diff --git a/include/hw/acpi/cpu.h b/include/hw/acpi/cpu.h > index ca32e07..0346f24 100644 > --- a/include/hw/acpi/cpu.h > +++ b/include/hw/acpi/cpu.h > @@ -45,7 +45,9 @@ void acpi_cpu_unplug_cb(CPUHotplugState *cpu_st, > void cpu_hotplug_hw_init(MemoryRegion *as, Object *owner, > CPUHotplugState *state, hwaddr base_addr); > > -void build_cpus_aml(Aml *table, MachineState *machine, bool apci1_compat); > +void build_cpus_aml(Aml *table, MachineState *machine, bool apci1_compat, > + const char *res_root, const char *event_handler_method, > + hwaddr io_base); > > extern const VMStateDescription vmstate_cpu_hotplug; > #define VMSTATE_CPU_HOTPLUG(cpuhp, state) \ > -- > 1.8.3.1