@@ -43,9 +43,15 @@
#define PCI_BASE 0xae00
#define PCI_EJ_BASE 0xae08
#define PCI_RMV_BASE 0xae0c
+#define PROC_BASE 0xaf00
+#define PIIX4_CPU_HOTPLUG_STATUS 4
#define PIIX4_PCI_HOTPLUG_STATUS 2
+struct gpe_regs {
+ uint8_t cpus_sts[32];
+};
+
struct pci_status {
uint32_t up;
uint32_t down;
@@ -71,6 +77,7 @@ typedef struct PIIX4PMState {
/* for pci hotplug */
ACPIGPE gpe;
+ struct gpe_regs gpe_cpu;
struct pci_status pci0_status;
uint32_t pci0_hotplug_enable;
} PIIX4PMState;
@@ -90,7 +97,8 @@ static void pm_update_sci(PIIX4PMState *s)
ACPI_BITMASK_POWER_BUTTON_ENABLE |
ACPI_BITMASK_GLOBAL_LOCK_ENABLE |
ACPI_BITMASK_TIMER_ENABLE)) != 0) ||
- (((s->gpe.sts[0] & s->gpe.en[0]) & PIIX4_PCI_HOTPLUG_STATUS) != 0);
+ (((s->gpe.sts[0] & s->gpe.en[0]) &
+ (PIIX4_PCI_HOTPLUG_STATUS | PIIX4_CPU_HOTPLUG_STATUS)) != 0);
qemu_set_irq(s->irq, sci_level);
/* schedule a timer interruption if needed */
@@ -329,11 +337,16 @@ static void piix4_pm_machine_ready(Notifier *n, void *opaque)
}
+static PIIX4PMState *global_piix4_pm_state; /* cpu hotadd */
+
static int piix4_pm_initfn(PCIDevice *dev)
{
PIIX4PMState *s = DO_UPCAST(PIIX4PMState, dev, dev);
uint8_t *pci_conf;
+ /* for cpu hotadd */
+ global_piix4_pm_state = s;
+
pci_conf = s->dev.config;
pci_conf[0x06] = 0x80;
pci_conf[0x07] = 0x02;
@@ -425,8 +438,17 @@ device_init(piix4_pm_register);
static uint32_t gpe_readb(void *opaque, uint32_t addr)
{
PIIX4PMState *s = opaque;
- uint32_t val = acpi_gpe_ioport_readb(&s->gpe, addr);
+ uint32_t val = 0;
+ struct gpe_regs *g = &s->gpe_cpu;
+ switch (addr) {
+ case PROC_BASE ... PROC_BASE+31:
+ val = g->cpus_sts[addr - PROC_BASE];
+ break;
+ default:
+ val = acpi_gpe_ioport_readb(&s->gpe, addr);
+ }
+
PIIX4_DPRINTF("gpe read %x == %x\n", addr, val);
return val;
}
@@ -519,11 +541,20 @@ static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev,
static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s)
{
struct pci_status *pci0_status = &s->pci0_status;
+ int i = 0, cpus = smp_cpus;
+ while (cpus > 0) {
+ s->gpe_cpu.cpus_sts[i++] = (cpus < 8) ? (1 << cpus) - 1 : 0xff;
+ cpus -= 8;
+ }
+
register_ioport_write(GPE_BASE, GPE_LEN, 1, gpe_writeb, s);
register_ioport_read(GPE_BASE, GPE_LEN, 1, gpe_readb, s);
acpi_gpe_blk(&s->gpe, GPE_BASE);
+ register_ioport_write(PROC_BASE, 32, 1, gpe_writeb, s);
+ register_ioport_read(PROC_BASE, 32, 1, gpe_readb, s);
+
register_ioport_write(PCI_BASE, 8, 4, pcihotplug_write, pci0_status);
register_ioport_read(PCI_BASE, 8, 4, pcihotplug_read, pci0_status);
@@ -536,6 +567,36 @@ static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s)
pci_bus_hotplug(bus, piix4_device_hotplug, &s->dev.qdev);
}
+static void enable_processor(PIIX4PMState *s, int cpu)
+{
+ struct gpe_regs *g = &s->gpe_cpu;
+ ACPIGPE *gpe = &s->gpe;
+
+ *gpe->sts = *gpe->sts | PIIX4_CPU_HOTPLUG_STATUS;
+ g->cpus_sts[cpu / 8] |= (1 << (cpu % 8));
+}
+
+static void disable_processor(PIIX4PMState *s, int cpu)
+{
+ struct gpe_regs *g = &s->gpe_cpu;
+ ACPIGPE *gpe = &s->gpe;
+
+ *gpe->sts = *gpe->sts | PIIX4_CPU_HOTPLUG_STATUS;
+ g->cpus_sts[cpu / 8] &= ~(1 << (cpu % 8));
+}
+
+void acpi_cpu_hot_plug(int cpu, int state)
+{
+ PIIX4PMState *s = global_piix4_pm_state;
+
+ if (state) {
+ enable_processor(s, cpu);
+ } else {
+ disable_processor(s, cpu);
+ }
+ pm_update_sci(s);
+}
+
static void enable_device(PIIX4PMState *s, int slot)
{
s->gpe.sts[0] |= PIIX4_PCI_HOTPLUG_STATUS;
@@ -163,6 +163,7 @@ extern size_t acpi_tables_len;
void acpi_bios_init(void);
int acpi_table_add(const char *table_desc);
+void acpi_cpu_hot_plug(int cpu, int state);
/* acpi_piix.c */
It's backport of acpi related cpu-hotplug code from qemu-kvm. Provides means to communicate cpu hot-plug events to guest OS and that works with current seabios. Signed-off-by: Igor Mammedov <imammedo@redhat.com> --- hw/acpi_piix4.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++- hw/pc.h | 1 + 2 files changed, 64 insertions(+), 2 deletions(-)