mirror of
git://git.yoctoproject.org/linux-yocto.git
synced 2025-07-05 13:25:20 +02:00
x86/acpi: Extract ACPI MADT wakeup code into a separate file
In order to prepare for the expansion of support for the ACPI MADT wakeup method, move the relevant code into a separate file. Introduce a new configuration option to clearly indicate dependencies without the use of ifdefs. There have been no functional changes. Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de> Reviewed-by: Baoquan He <bhe@redhat.com> Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com> Reviewed-by: Thomas Gleixner <tglx@linutronix.de> Acked-by: Borislav Petkov (AMD) <bp@alien8.de> Acked-by: Kai Huang <kai.huang@intel.com> Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Tested-by: Tao Liu <ltao@redhat.com> Link: https://lore.kernel.org/r/20240614095904.1345461-2-kirill.shutemov@linux.intel.com
This commit is contained in:
parent
54183d103d
commit
2b5e22afae
|
@ -1118,6 +1118,13 @@ config X86_LOCAL_APIC
|
|||
depends on X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_APIC || PCI_MSI
|
||||
select IRQ_DOMAIN_HIERARCHY
|
||||
|
||||
config ACPI_MADT_WAKEUP
|
||||
def_bool y
|
||||
depends on X86_64
|
||||
depends on ACPI
|
||||
depends on SMP
|
||||
depends on X86_LOCAL_APIC
|
||||
|
||||
config X86_IO_APIC
|
||||
def_bool y
|
||||
depends on X86_LOCAL_APIC || X86_UP_IOAPIC
|
||||
|
|
|
@ -78,6 +78,11 @@ static inline bool acpi_skip_set_wakeup_address(void)
|
|||
|
||||
#define acpi_skip_set_wakeup_address acpi_skip_set_wakeup_address
|
||||
|
||||
union acpi_subtable_headers;
|
||||
|
||||
int __init acpi_parse_mp_wake(union acpi_subtable_headers *header,
|
||||
const unsigned long end);
|
||||
|
||||
/*
|
||||
* Check if the CPU can handle C2 and deeper
|
||||
*/
|
||||
|
|
|
@ -4,6 +4,7 @@ obj-$(CONFIG_ACPI) += boot.o
|
|||
obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup_$(BITS).o
|
||||
obj-$(CONFIG_ACPI_APEI) += apei.o
|
||||
obj-$(CONFIG_ACPI_CPPC_LIB) += cppc.o
|
||||
obj-$(CONFIG_ACPI_MADT_WAKEUP) += madt_wakeup.o
|
||||
|
||||
ifneq ($(CONFIG_ACPI_PROCESSOR),)
|
||||
obj-y += cstate.o
|
||||
|
|
|
@ -67,13 +67,6 @@ static bool has_lapic_cpus __initdata;
|
|||
static bool acpi_support_online_capable;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
/* Physical address of the Multiprocessor Wakeup Structure mailbox */
|
||||
static u64 acpi_mp_wake_mailbox_paddr;
|
||||
/* Virtual address of the Multiprocessor Wakeup Structure mailbox */
|
||||
static struct acpi_madt_multiproc_wakeup_mailbox *acpi_mp_wake_mailbox;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_X86_IO_APIC
|
||||
/*
|
||||
* Locks related to IOAPIC hotplug
|
||||
|
@ -341,60 +334,6 @@ acpi_parse_lapic_nmi(union acpi_subtable_headers * header, const unsigned long e
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
static int acpi_wakeup_cpu(u32 apicid, unsigned long start_ip)
|
||||
{
|
||||
/*
|
||||
* Remap mailbox memory only for the first call to acpi_wakeup_cpu().
|
||||
*
|
||||
* Wakeup of secondary CPUs is fully serialized in the core code.
|
||||
* No need to protect acpi_mp_wake_mailbox from concurrent accesses.
|
||||
*/
|
||||
if (!acpi_mp_wake_mailbox) {
|
||||
acpi_mp_wake_mailbox = memremap(acpi_mp_wake_mailbox_paddr,
|
||||
sizeof(*acpi_mp_wake_mailbox),
|
||||
MEMREMAP_WB);
|
||||
}
|
||||
|
||||
/*
|
||||
* Mailbox memory is shared between the firmware and OS. Firmware will
|
||||
* listen on mailbox command address, and once it receives the wakeup
|
||||
* command, the CPU associated with the given apicid will be booted.
|
||||
*
|
||||
* The value of 'apic_id' and 'wakeup_vector' must be visible to the
|
||||
* firmware before the wakeup command is visible. smp_store_release()
|
||||
* ensures ordering and visibility.
|
||||
*/
|
||||
acpi_mp_wake_mailbox->apic_id = apicid;
|
||||
acpi_mp_wake_mailbox->wakeup_vector = start_ip;
|
||||
smp_store_release(&acpi_mp_wake_mailbox->command,
|
||||
ACPI_MP_WAKE_COMMAND_WAKEUP);
|
||||
|
||||
/*
|
||||
* Wait for the CPU to wake up.
|
||||
*
|
||||
* The CPU being woken up is essentially in a spin loop waiting to be
|
||||
* woken up. It should not take long for it wake up and acknowledge by
|
||||
* zeroing out ->command.
|
||||
*
|
||||
* ACPI specification doesn't provide any guidance on how long kernel
|
||||
* has to wait for a wake up acknowledgement. It also doesn't provide
|
||||
* a way to cancel a wake up request if it takes too long.
|
||||
*
|
||||
* In TDX environment, the VMM has control over how long it takes to
|
||||
* wake up secondary. It can postpone scheduling secondary vCPU
|
||||
* indefinitely. Giving up on wake up request and reporting error opens
|
||||
* possible attack vector for VMM: it can wake up a secondary CPU when
|
||||
* kernel doesn't expect it. Wait until positive result of the wake up
|
||||
* request.
|
||||
*/
|
||||
while (READ_ONCE(acpi_mp_wake_mailbox->command))
|
||||
cpu_relax();
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_X86_64 */
|
||||
#endif /* CONFIG_X86_LOCAL_APIC */
|
||||
|
||||
#ifdef CONFIG_X86_IO_APIC
|
||||
|
@ -1124,29 +1063,6 @@ static int __init acpi_parse_madt_lapic_entries(void)
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
static int __init acpi_parse_mp_wake(union acpi_subtable_headers *header,
|
||||
const unsigned long end)
|
||||
{
|
||||
struct acpi_madt_multiproc_wakeup *mp_wake;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_SMP))
|
||||
return -ENODEV;
|
||||
|
||||
mp_wake = (struct acpi_madt_multiproc_wakeup *)header;
|
||||
if (BAD_MADT_ENTRY(mp_wake, end))
|
||||
return -EINVAL;
|
||||
|
||||
acpi_table_print_madt_entry(&header->common);
|
||||
|
||||
acpi_mp_wake_mailbox_paddr = mp_wake->base_address;
|
||||
|
||||
apic_update_callback(wakeup_secondary_cpu_64, acpi_wakeup_cpu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_X86_64 */
|
||||
#endif /* CONFIG_X86_LOCAL_APIC */
|
||||
|
||||
#ifdef CONFIG_X86_IO_APIC
|
||||
|
@ -1343,7 +1259,7 @@ static void __init acpi_process_madt(void)
|
|||
smp_found_config = 1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
#ifdef CONFIG_ACPI_MADT_WAKEUP
|
||||
/*
|
||||
* Parse MADT MP Wake entry.
|
||||
*/
|
||||
|
|
82
arch/x86/kernel/acpi/madt_wakeup.c
Normal file
82
arch/x86/kernel/acpi/madt_wakeup.c
Normal file
|
@ -0,0 +1,82 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/io.h>
|
||||
#include <asm/apic.h>
|
||||
#include <asm/barrier.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
/* Physical address of the Multiprocessor Wakeup Structure mailbox */
|
||||
static u64 acpi_mp_wake_mailbox_paddr;
|
||||
|
||||
/* Virtual address of the Multiprocessor Wakeup Structure mailbox */
|
||||
static struct acpi_madt_multiproc_wakeup_mailbox *acpi_mp_wake_mailbox;
|
||||
|
||||
static int acpi_wakeup_cpu(u32 apicid, unsigned long start_ip)
|
||||
{
|
||||
/*
|
||||
* Remap mailbox memory only for the first call to acpi_wakeup_cpu().
|
||||
*
|
||||
* Wakeup of secondary CPUs is fully serialized in the core code.
|
||||
* No need to protect acpi_mp_wake_mailbox from concurrent accesses.
|
||||
*/
|
||||
if (!acpi_mp_wake_mailbox) {
|
||||
acpi_mp_wake_mailbox = memremap(acpi_mp_wake_mailbox_paddr,
|
||||
sizeof(*acpi_mp_wake_mailbox),
|
||||
MEMREMAP_WB);
|
||||
}
|
||||
|
||||
/*
|
||||
* Mailbox memory is shared between the firmware and OS. Firmware will
|
||||
* listen on mailbox command address, and once it receives the wakeup
|
||||
* command, the CPU associated with the given apicid will be booted.
|
||||
*
|
||||
* The value of 'apic_id' and 'wakeup_vector' must be visible to the
|
||||
* firmware before the wakeup command is visible. smp_store_release()
|
||||
* ensures ordering and visibility.
|
||||
*/
|
||||
acpi_mp_wake_mailbox->apic_id = apicid;
|
||||
acpi_mp_wake_mailbox->wakeup_vector = start_ip;
|
||||
smp_store_release(&acpi_mp_wake_mailbox->command,
|
||||
ACPI_MP_WAKE_COMMAND_WAKEUP);
|
||||
|
||||
/*
|
||||
* Wait for the CPU to wake up.
|
||||
*
|
||||
* The CPU being woken up is essentially in a spin loop waiting to be
|
||||
* woken up. It should not take long for it wake up and acknowledge by
|
||||
* zeroing out ->command.
|
||||
*
|
||||
* ACPI specification doesn't provide any guidance on how long kernel
|
||||
* has to wait for a wake up acknowledgment. It also doesn't provide
|
||||
* a way to cancel a wake up request if it takes too long.
|
||||
*
|
||||
* In TDX environment, the VMM has control over how long it takes to
|
||||
* wake up secondary. It can postpone scheduling secondary vCPU
|
||||
* indefinitely. Giving up on wake up request and reporting error opens
|
||||
* possible attack vector for VMM: it can wake up a secondary CPU when
|
||||
* kernel doesn't expect it. Wait until positive result of the wake up
|
||||
* request.
|
||||
*/
|
||||
while (READ_ONCE(acpi_mp_wake_mailbox->command))
|
||||
cpu_relax();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __init acpi_parse_mp_wake(union acpi_subtable_headers *header,
|
||||
const unsigned long end)
|
||||
{
|
||||
struct acpi_madt_multiproc_wakeup *mp_wake;
|
||||
|
||||
mp_wake = (struct acpi_madt_multiproc_wakeup *)header;
|
||||
if (BAD_MADT_ENTRY(mp_wake, end))
|
||||
return -EINVAL;
|
||||
|
||||
acpi_table_print_madt_entry(&header->common);
|
||||
|
||||
acpi_mp_wake_mailbox_paddr = mp_wake->base_address;
|
||||
|
||||
apic_update_callback(wakeup_secondary_cpu_64, acpi_wakeup_cpu);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user