![Thomas Gleixner](/assets/img/avatar_default.png)
Based on 1 normalized pattern(s): 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 this program is distributed in the hope that it will be useful but without any warranty without even the implied warranty of merchantability or fitness for a particular purpose see the gnu general public license for more details you should have received a copy of the gnu general public license along with this program if not see http www gnu org licenses extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference in 503 file(s). Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Alexios Zavras <alexios.zavras@intel.com> Reviewed-by: Allison Randal <allison@lohutok.net> Reviewed-by: Enrico Weigelt <info@metux.net> Cc: linux-spdx@vger.kernel.org Link: https://lkml.kernel.org/r/20190602204653.811534538@linutronix.de Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
126 lines
2.9 KiB
C
126 lines
2.9 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Spin Table SMP initialisation
|
|
*
|
|
* Copyright (C) 2013 ARM Ltd.
|
|
*/
|
|
|
|
#include <linux/delay.h>
|
|
#include <linux/init.h>
|
|
#include <linux/of.h>
|
|
#include <linux/smp.h>
|
|
#include <linux/types.h>
|
|
#include <linux/mm.h>
|
|
|
|
#include <asm/cacheflush.h>
|
|
#include <asm/cpu_ops.h>
|
|
#include <asm/cputype.h>
|
|
#include <asm/io.h>
|
|
#include <asm/smp_plat.h>
|
|
|
|
extern void secondary_holding_pen(void);
|
|
volatile unsigned long __section(".mmuoff.data.read")
|
|
secondary_holding_pen_release = INVALID_HWID;
|
|
|
|
static phys_addr_t cpu_release_addr[NR_CPUS];
|
|
|
|
/*
|
|
* Write secondary_holding_pen_release in a way that is guaranteed to be
|
|
* visible to all observers, irrespective of whether they're taking part
|
|
* in coherency or not. This is necessary for the hotplug code to work
|
|
* reliably.
|
|
*/
|
|
static void write_pen_release(u64 val)
|
|
{
|
|
void *start = (void *)&secondary_holding_pen_release;
|
|
unsigned long size = sizeof(secondary_holding_pen_release);
|
|
|
|
secondary_holding_pen_release = val;
|
|
__flush_dcache_area(start, size);
|
|
}
|
|
|
|
|
|
static int smp_spin_table_cpu_init(unsigned int cpu)
|
|
{
|
|
struct device_node *dn;
|
|
int ret;
|
|
|
|
dn = of_get_cpu_node(cpu, NULL);
|
|
if (!dn)
|
|
return -ENODEV;
|
|
|
|
/*
|
|
* Determine the address from which the CPU is polling.
|
|
*/
|
|
ret = of_property_read_u64(dn, "cpu-release-addr",
|
|
&cpu_release_addr[cpu]);
|
|
if (ret)
|
|
pr_err("CPU %d: missing or invalid cpu-release-addr property\n",
|
|
cpu);
|
|
|
|
of_node_put(dn);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int smp_spin_table_cpu_prepare(unsigned int cpu)
|
|
{
|
|
__le64 __iomem *release_addr;
|
|
|
|
if (!cpu_release_addr[cpu])
|
|
return -ENODEV;
|
|
|
|
/*
|
|
* The cpu-release-addr may or may not be inside the linear mapping.
|
|
* As ioremap_cache will either give us a new mapping or reuse the
|
|
* existing linear mapping, we can use it to cover both cases. In
|
|
* either case the memory will be MT_NORMAL.
|
|
*/
|
|
release_addr = ioremap_cache(cpu_release_addr[cpu],
|
|
sizeof(*release_addr));
|
|
if (!release_addr)
|
|
return -ENOMEM;
|
|
|
|
/*
|
|
* We write the release address as LE regardless of the native
|
|
* endianess of the kernel. Therefore, any boot-loaders that
|
|
* read this address need to convert this address to the
|
|
* boot-loader's endianess before jumping. This is mandated by
|
|
* the boot protocol.
|
|
*/
|
|
writeq_relaxed(__pa_symbol(secondary_holding_pen), release_addr);
|
|
__flush_dcache_area((__force void *)release_addr,
|
|
sizeof(*release_addr));
|
|
|
|
/*
|
|
* Send an event to wake up the secondary CPU.
|
|
*/
|
|
sev();
|
|
|
|
iounmap(release_addr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int smp_spin_table_cpu_boot(unsigned int cpu)
|
|
{
|
|
/*
|
|
* Update the pen release flag.
|
|
*/
|
|
write_pen_release(cpu_logical_map(cpu));
|
|
|
|
/*
|
|
* Send an event, causing the secondaries to read pen_release.
|
|
*/
|
|
sev();
|
|
|
|
return 0;
|
|
}
|
|
|
|
const struct cpu_operations smp_spin_table_ops = {
|
|
.name = "spin-table",
|
|
.cpu_init = smp_spin_table_cpu_init,
|
|
.cpu_prepare = smp_spin_table_cpu_prepare,
|
|
.cpu_boot = smp_spin_table_cpu_boot,
|
|
};
|