2019-06-03 08:44:50 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2016-01-26 14:10:38 +03:00
/*
* ARM64 ACPI Parking Protocol implementation
*
* Authors : Lorenzo Pieralisi < lorenzo . pieralisi @ arm . com >
* Mark Salter < msalter @ redhat . com >
*/
# include <linux/acpi.h>
2017-01-11 00:35:49 +03:00
# include <linux/mm.h>
2016-01-26 14:10:38 +03:00
# include <linux/types.h>
# include <asm/cpu_ops.h>
2016-02-26 14:50:12 +03:00
struct parking_protocol_mailbox {
__le32 cpu_id ;
__le32 reserved ;
__le64 entry_point ;
} ;
2016-01-26 14:10:38 +03:00
struct cpu_mailbox_entry {
2016-02-26 14:50:12 +03:00
struct parking_protocol_mailbox __iomem * mailbox ;
2016-01-26 14:10:38 +03:00
phys_addr_t mailbox_addr ;
u8 version ;
u8 gic_cpu_id ;
} ;
static struct cpu_mailbox_entry cpu_mailbox_entries [ NR_CPUS ] ;
void __init acpi_set_mailbox_entry ( int cpu ,
struct acpi_madt_generic_interrupt * p )
{
struct cpu_mailbox_entry * cpu_entry = & cpu_mailbox_entries [ cpu ] ;
cpu_entry - > mailbox_addr = p - > parked_address ;
cpu_entry - > version = p - > parking_version ;
cpu_entry - > gic_cpu_id = p - > cpu_interface_number ;
}
bool acpi_parking_protocol_valid ( int cpu )
{
struct cpu_mailbox_entry * cpu_entry = & cpu_mailbox_entries [ cpu ] ;
return cpu_entry - > mailbox_addr & & cpu_entry - > version ;
}
static int acpi_parking_protocol_cpu_init ( unsigned int cpu )
{
pr_debug ( " %s: ACPI parked addr=%llx \n " , __func__ ,
cpu_mailbox_entries [ cpu ] . mailbox_addr ) ;
return 0 ;
}
static int acpi_parking_protocol_cpu_prepare ( unsigned int cpu )
{
return 0 ;
}
static int acpi_parking_protocol_cpu_boot ( unsigned int cpu )
{
struct cpu_mailbox_entry * cpu_entry = & cpu_mailbox_entries [ cpu ] ;
struct parking_protocol_mailbox __iomem * mailbox ;
2017-06-28 17:58:07 +03:00
u32 cpu_id ;
2016-01-26 14:10:38 +03:00
/*
* Map mailbox memory with attribute device nGnRE ( ie ioremap -
* this deviates from the parking protocol specifications since
* the mailboxes are required to be mapped nGnRnE ; the attribute
* discrepancy is harmless insofar as the protocol specification
* is concerned ) .
* If the mailbox is mistakenly allocated in the linear mapping
* by FW ioremap will fail since the mapping will be prevented
* by the kernel ( it clashes with the linear mapping attributes
* specifications ) .
*/
mailbox = ioremap ( cpu_entry - > mailbox_addr , sizeof ( * mailbox ) ) ;
if ( ! mailbox )
return - EIO ;
cpu_id = readl_relaxed ( & mailbox - > cpu_id ) ;
/*
* Check if firmware has set - up the mailbox entry properly
* before kickstarting the respective cpu .
*/
if ( cpu_id ! = ~ 0U ) {
iounmap ( mailbox ) ;
return - ENXIO ;
}
2016-02-26 14:50:12 +03:00
/*
* stash the mailbox address mapping to use it for further FW
* checks in the postboot method
*/
cpu_entry - > mailbox = mailbox ;
2016-01-26 14:10:38 +03:00
/*
* We write the entry point and cpu id as LE regardless of the
* native endianness of the kernel . Therefore , any boot - loaders
* that read this address need to convert this address to the
* Boot - Loader ' s endianness before jumping .
*/
2022-09-09 00:54:55 +03:00
writeq_relaxed ( __pa_symbol ( secondary_entry ) ,
2021-04-08 21:28:38 +03:00
& mailbox - > entry_point ) ;
2016-01-26 14:10:38 +03:00
writel_relaxed ( cpu_entry - > gic_cpu_id , & mailbox - > cpu_id ) ;
2023-09-06 19:02:58 +03:00
arch_send_wakeup_ipi ( cpu ) ;
2016-01-26 14:10:38 +03:00
return 0 ;
}
static void acpi_parking_protocol_cpu_postboot ( void )
{
int cpu = smp_processor_id ( ) ;
struct cpu_mailbox_entry * cpu_entry = & cpu_mailbox_entries [ cpu ] ;
2016-02-26 14:50:12 +03:00
struct parking_protocol_mailbox __iomem * mailbox = cpu_entry - > mailbox ;
2017-06-28 17:58:07 +03:00
u64 entry_point ;
2016-01-26 14:10:38 +03:00
2017-06-26 16:16:25 +03:00
entry_point = readq_relaxed ( & mailbox - > entry_point ) ;
2016-01-26 14:10:38 +03:00
/*
* Check if firmware has cleared the entry_point as expected
* by the protocol specification .
*/
WARN_ON ( entry_point ) ;
}
const struct cpu_operations acpi_parking_protocol_ops = {
. name = " parking-protocol " ,
. cpu_init = acpi_parking_protocol_cpu_init ,
. cpu_prepare = acpi_parking_protocol_cpu_prepare ,
. cpu_boot = acpi_parking_protocol_cpu_boot ,
. cpu_postboot = acpi_parking_protocol_cpu_postboot
} ;