cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

platsmp.c (2833B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (C) 2014 Marvell Technology Group Ltd.
      4 *
      5 * Antoine Ténart <antoine.tenart@free-electrons.com>
      6 */
      7
      8#include <linux/io.h>
      9#include <linux/delay.h>
     10#include <linux/of.h>
     11#include <linux/of_address.h>
     12
     13#include <asm/cacheflush.h>
     14#include <asm/cp15.h>
     15#include <asm/memory.h>
     16#include <asm/smp_plat.h>
     17#include <asm/smp_scu.h>
     18
     19/*
     20 * There are two reset registers, one with self-clearing (SC)
     21 * reset and one with non-self-clearing reset (NON_SC).
     22 */
     23#define CPU_RESET_SC		0x00
     24#define CPU_RESET_NON_SC	0x20
     25
     26#define RESET_VECT		0x00
     27#define SW_RESET_ADDR		0x94
     28
     29extern u32 boot_inst;
     30
     31static void __iomem *cpu_ctrl;
     32
     33static inline void berlin_perform_reset_cpu(unsigned int cpu)
     34{
     35	u32 val;
     36
     37	val = readl(cpu_ctrl + CPU_RESET_NON_SC);
     38	val &= ~BIT(cpu_logical_map(cpu));
     39	writel(val, cpu_ctrl + CPU_RESET_NON_SC);
     40	val |= BIT(cpu_logical_map(cpu));
     41	writel(val, cpu_ctrl + CPU_RESET_NON_SC);
     42}
     43
     44static int berlin_boot_secondary(unsigned int cpu, struct task_struct *idle)
     45{
     46	if (!cpu_ctrl)
     47		return -EFAULT;
     48
     49	/*
     50	 * Reset the CPU, making it to execute the instruction in the reset
     51	 * exception vector.
     52	 */
     53	berlin_perform_reset_cpu(cpu);
     54
     55	return 0;
     56}
     57
     58static void __init berlin_smp_prepare_cpus(unsigned int max_cpus)
     59{
     60	struct device_node *np;
     61	void __iomem *scu_base;
     62	void __iomem *vectors_base;
     63
     64	np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
     65	scu_base = of_iomap(np, 0);
     66	of_node_put(np);
     67	if (!scu_base)
     68		return;
     69
     70	np = of_find_compatible_node(NULL, NULL, "marvell,berlin-cpu-ctrl");
     71	cpu_ctrl = of_iomap(np, 0);
     72	of_node_put(np);
     73	if (!cpu_ctrl)
     74		goto unmap_scu;
     75
     76	vectors_base = ioremap(VECTORS_BASE, SZ_32K);
     77	if (!vectors_base)
     78		goto unmap_scu;
     79
     80	scu_enable(scu_base);
     81
     82	/*
     83	 * Write the first instruction the CPU will execute after being reset
     84	 * in the reset exception vector.
     85	 */
     86	writel(boot_inst, vectors_base + RESET_VECT);
     87
     88	/*
     89	 * Write the secondary startup address into the SW reset address
     90	 * vector. This is used by boot_inst.
     91	 */
     92	writel(__pa_symbol(secondary_startup), vectors_base + SW_RESET_ADDR);
     93
     94	iounmap(vectors_base);
     95unmap_scu:
     96	iounmap(scu_base);
     97}
     98
     99#ifdef CONFIG_HOTPLUG_CPU
    100static void berlin_cpu_die(unsigned int cpu)
    101{
    102	v7_exit_coherency_flush(louis);
    103	while (1)
    104		cpu_do_idle();
    105}
    106
    107static int berlin_cpu_kill(unsigned int cpu)
    108{
    109	u32 val;
    110
    111	val = readl(cpu_ctrl + CPU_RESET_NON_SC);
    112	val &= ~BIT(cpu_logical_map(cpu));
    113	writel(val, cpu_ctrl + CPU_RESET_NON_SC);
    114
    115	return 1;
    116}
    117#endif
    118
    119static const struct smp_operations berlin_smp_ops __initconst = {
    120	.smp_prepare_cpus	= berlin_smp_prepare_cpus,
    121	.smp_boot_secondary	= berlin_boot_secondary,
    122#ifdef CONFIG_HOTPLUG_CPU
    123	.cpu_die		= berlin_cpu_die,
    124	.cpu_kill		= berlin_cpu_kill,
    125#endif
    126};
    127CPU_METHOD_OF_DECLARE(berlin_smp, "marvell,berlin-smp", &berlin_smp_ops);