mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-25 21:17:50 +07:00
525d4015e6
Current vexpress smp init code detects whether to override the default smp ops with MCPM smp ops by matching the "cci-400" compatible string, in that MCPM requires control over CCI ports to manage low-power states entry/exit. The "cci-400" compatible string check is a necessary but not sufficient condition for MCPM to work, because the cci-400 can be made visible to the kernel, but firmware can nonetheless disable non-secure CCI ports control, while still allowing PMU access; if booted in non-secure world, the kernel would still blindly override smp operations with MCPM operations, resulting in kernel faults when the CCI ports programming interface is accessed from non-secure world. This means that the "cci-400" compatible string check would result in a false positive in systems that eg boot in HYP mode, where CCI ports non-secure access is explicitly not allowed, and it is reported in the respective device tree nodes with CCI ports marked as disabled. Refactor the smp operations initialization to make sure that the kernel is actually allowed to take control over CCI ports (by enabling MCPM smp operations) before overriding default vexpress smp operations. Cc: Liviu Dudau <liviu.dudau@arm.com> Cc: Marc Zyngier <marc.zyngier@arm.com> Acked-by: Nicolas Pitre <nico@linaro.org> Tested-by: Jon Medhurst <tixy@linaro.org> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
93 lines
2.3 KiB
C
93 lines
2.3 KiB
C
/*
|
|
* linux/arch/arm/mach-vexpress/platsmp.c
|
|
*
|
|
* Copyright (C) 2002 ARM Ltd.
|
|
* All Rights Reserved
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*/
|
|
#include <linux/init.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/smp.h>
|
|
#include <linux/io.h>
|
|
#include <linux/of_address.h>
|
|
#include <linux/vexpress.h>
|
|
|
|
#include <asm/mcpm.h>
|
|
#include <asm/smp_scu.h>
|
|
#include <asm/mach/map.h>
|
|
|
|
#include <plat/platsmp.h>
|
|
|
|
#include "core.h"
|
|
|
|
bool __init vexpress_smp_init_ops(void)
|
|
{
|
|
#ifdef CONFIG_MCPM
|
|
int cpu;
|
|
struct device_node *cpu_node, *cci_node;
|
|
|
|
/*
|
|
* The best way to detect a multi-cluster configuration
|
|
* is to detect if the kernel can take over CCI ports
|
|
* control. Loop over possible CPUs and check if CCI
|
|
* port control is available.
|
|
* Override the default vexpress_smp_ops if so.
|
|
*/
|
|
for_each_possible_cpu(cpu) {
|
|
bool available;
|
|
|
|
cpu_node = of_get_cpu_node(cpu, NULL);
|
|
if (WARN(!cpu_node, "Missing cpu device node!"))
|
|
return false;
|
|
|
|
cci_node = of_parse_phandle(cpu_node, "cci-control-port", 0);
|
|
available = cci_node && of_device_is_available(cci_node);
|
|
of_node_put(cci_node);
|
|
of_node_put(cpu_node);
|
|
|
|
if (!available)
|
|
return false;
|
|
}
|
|
|
|
mcpm_smp_set_ops();
|
|
return true;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
static const struct of_device_id vexpress_smp_dt_scu_match[] __initconst = {
|
|
{ .compatible = "arm,cortex-a5-scu", },
|
|
{ .compatible = "arm,cortex-a9-scu", },
|
|
{}
|
|
};
|
|
|
|
static void __init vexpress_smp_dt_prepare_cpus(unsigned int max_cpus)
|
|
{
|
|
struct device_node *scu = of_find_matching_node(NULL,
|
|
vexpress_smp_dt_scu_match);
|
|
|
|
if (scu)
|
|
scu_enable(of_iomap(scu, 0));
|
|
|
|
/*
|
|
* Write the address of secondary startup into the
|
|
* system-wide flags register. The boot monitor waits
|
|
* until it receives a soft interrupt, and then the
|
|
* secondary CPU branches to this address.
|
|
*/
|
|
vexpress_flags_set(virt_to_phys(versatile_secondary_startup));
|
|
}
|
|
|
|
const struct smp_operations vexpress_smp_dt_ops __initconst = {
|
|
.smp_prepare_cpus = vexpress_smp_dt_prepare_cpus,
|
|
.smp_secondary_init = versatile_secondary_init,
|
|
.smp_boot_secondary = versatile_boot_secondary,
|
|
#ifdef CONFIG_HOTPLUG_CPU
|
|
.cpu_die = vexpress_cpu_die,
|
|
#endif
|
|
};
|