acpi: cpuhp: introduce 'firmware performs eject' status/control bits

Adds bit #4 to status/control field of CPU hotplug MMIO interface.
New bit will be used OSPM to mark CPUs as pending for removal by firmware,
when it calls _EJ0 method on CPU device node. Later on, when firmware
sees this bit set, it will perform CPU eject which will clear bit #4
as well.

Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Message-Id: <20201207140739.3829993-3-imammedo@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
Igor Mammedov 2020-12-07 09:07:33 -05:00 committed by Michael S. Tsirkin
parent 0657c657eb
commit 1e6107d901
4 changed files with 28 additions and 6 deletions

View File

@ -56,8 +56,11 @@ read access:
no device check event to OSPM was issued. no device check event to OSPM was issued.
It's valid only when bit 0 is set. It's valid only when bit 0 is set.
2: Device remove event, used to distinguish device for which 2: Device remove event, used to distinguish device for which
no device eject request to OSPM was issued. no device eject request to OSPM was issued. Firmware must
3-7: reserved and should be ignored by OSPM ignore this bit.
3: reserved and should be ignored by OSPM
4: if set to 1, OSPM requests firmware to perform device eject.
5-7: reserved and should be ignored by OSPM
[0x5-0x7] reserved [0x5-0x7] reserved
[0x8] Command data: (DWORD access) [0x8] Command data: (DWORD access)
contains 0 unless value last stored in 'Command field' is one of: contains 0 unless value last stored in 'Command field' is one of:
@ -79,10 +82,16 @@ write access:
selected CPU device selected CPU device
2: if set to 1 clears device remove event, set by OSPM 2: if set to 1 clears device remove event, set by OSPM
after it has emitted device eject request for the after it has emitted device eject request for the
selected CPU device selected CPU device.
3: if set to 1 initiates device eject, set by OSPM when it 3: if set to 1 initiates device eject, set by OSPM when it
triggers CPU device removal and calls _EJ0 method triggers CPU device removal and calls _EJ0 method or by firmware
4-7: reserved, OSPM must clear them before writing to register when bit #4 is set. In case bit #4 were set, it's cleared as
part of device eject.
4: if set to 1, OSPM hands over device eject to firmware.
Firmware shall issue device eject request as described above
(bit #3) and OSPM should not touch device eject bit (#3) in case
it's asked firmware to perform CPU device eject.
5-7: reserved, OSPM must clear them before writing to register
[0x5] Command field: (1 byte access) [0x5] Command field: (1 byte access)
value: value:
0: selects a CPU device with inserting/removing events and 0: selects a CPU device with inserting/removing events and

View File

@ -71,6 +71,7 @@ static uint64_t cpu_hotplug_rd(void *opaque, hwaddr addr, unsigned size)
val |= cdev->cpu ? 1 : 0; val |= cdev->cpu ? 1 : 0;
val |= cdev->is_inserting ? 2 : 0; val |= cdev->is_inserting ? 2 : 0;
val |= cdev->is_removing ? 4 : 0; val |= cdev->is_removing ? 4 : 0;
val |= cdev->fw_remove ? 16 : 0;
trace_cpuhp_acpi_read_flags(cpu_st->selector, val); trace_cpuhp_acpi_read_flags(cpu_st->selector, val);
break; break;
case ACPI_CPU_CMD_DATA_OFFSET_RW: case ACPI_CPU_CMD_DATA_OFFSET_RW:
@ -148,6 +149,14 @@ static void cpu_hotplug_wr(void *opaque, hwaddr addr, uint64_t data,
hotplug_ctrl = qdev_get_hotplug_handler(dev); hotplug_ctrl = qdev_get_hotplug_handler(dev);
hotplug_handler_unplug(hotplug_ctrl, dev, NULL); hotplug_handler_unplug(hotplug_ctrl, dev, NULL);
object_unparent(OBJECT(dev)); object_unparent(OBJECT(dev));
cdev->fw_remove = false;
} else if (data & 16) {
if (!cdev->cpu || cdev->cpu == first_cpu) {
trace_cpuhp_acpi_fw_remove_invalid_cpu(cpu_st->selector);
break;
}
trace_cpuhp_acpi_fw_remove_cpu(cpu_st->selector);
cdev->fw_remove = true;
} }
break; break;
case ACPI_CPU_CMD_OFFSET_WR: case ACPI_CPU_CMD_OFFSET_WR:
@ -159,7 +168,8 @@ static void cpu_hotplug_wr(void *opaque, hwaddr addr, uint64_t data,
do { do {
cdev = &cpu_st->devs[iter]; cdev = &cpu_st->devs[iter];
if (cdev->is_inserting || cdev->is_removing) { if (cdev->is_inserting || cdev->is_removing ||
cdev->fw_remove) {
cpu_st->selector = iter; cpu_st->selector = iter;
trace_cpuhp_acpi_cpu_has_events(cpu_st->selector, trace_cpuhp_acpi_cpu_has_events(cpu_st->selector,
cdev->is_inserting, cdev->is_removing); cdev->is_inserting, cdev->is_removing);

View File

@ -29,6 +29,8 @@ cpuhp_acpi_clear_inserting_evt(uint32_t idx) "idx[0x%"PRIx32"]"
cpuhp_acpi_clear_remove_evt(uint32_t idx) "idx[0x%"PRIx32"]" cpuhp_acpi_clear_remove_evt(uint32_t idx) "idx[0x%"PRIx32"]"
cpuhp_acpi_ejecting_invalid_cpu(uint32_t idx) "0x%"PRIx32 cpuhp_acpi_ejecting_invalid_cpu(uint32_t idx) "0x%"PRIx32
cpuhp_acpi_ejecting_cpu(uint32_t idx) "0x%"PRIx32 cpuhp_acpi_ejecting_cpu(uint32_t idx) "0x%"PRIx32
cpuhp_acpi_fw_remove_invalid_cpu(uint32_t idx) "0x%"PRIx32
cpuhp_acpi_fw_remove_cpu(uint32_t idx) "0x%"PRIx32
cpuhp_acpi_write_ost_ev(uint32_t slot, uint32_t ev) "idx[0x%"PRIx32"] OST EVENT: 0x%"PRIx32 cpuhp_acpi_write_ost_ev(uint32_t slot, uint32_t ev) "idx[0x%"PRIx32"] OST EVENT: 0x%"PRIx32
cpuhp_acpi_write_ost_status(uint32_t slot, uint32_t st) "idx[0x%"PRIx32"] OST STATUS: 0x%"PRIx32 cpuhp_acpi_write_ost_status(uint32_t slot, uint32_t st) "idx[0x%"PRIx32"] OST STATUS: 0x%"PRIx32

View File

@ -22,6 +22,7 @@ typedef struct AcpiCpuStatus {
uint64_t arch_id; uint64_t arch_id;
bool is_inserting; bool is_inserting;
bool is_removing; bool is_removing;
bool fw_remove;
uint32_t ost_event; uint32_t ost_event;
uint32_t ost_status; uint32_t ost_status;
} AcpiCpuStatus; } AcpiCpuStatus;