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

bcm63xx_smp.c (4162B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Broadcom BCM63138 DSL SoCs SMP support code
      4 *
      5 * Copyright (C) 2015, Broadcom Corporation
      6 */
      7
      8#include <linux/delay.h>
      9#include <linux/init.h>
     10#include <linux/smp.h>
     11#include <linux/io.h>
     12#include <linux/of.h>
     13#include <linux/of_address.h>
     14
     15#include <asm/cacheflush.h>
     16#include <asm/smp_scu.h>
     17#include <asm/smp_plat.h>
     18#include <asm/vfp.h>
     19
     20#include "bcm63xx_smp.h"
     21
     22/* Size of mapped Cortex A9 SCU address space */
     23#define CORTEX_A9_SCU_SIZE	0x58
     24
     25/*
     26 * Enable the Cortex A9 Snoop Control Unit
     27 *
     28 * By the time this is called we already know there are multiple
     29 * cores present.  We assume we're running on a Cortex A9 processor,
     30 * so any trouble getting the base address register or getting the
     31 * SCU base is a problem.
     32 *
     33 * Return 0 if successful or an error code otherwise.
     34 */
     35static int __init scu_a9_enable(void)
     36{
     37	unsigned long config_base;
     38	void __iomem *scu_base;
     39	unsigned int i, ncores;
     40
     41	if (!scu_a9_has_base()) {
     42		pr_err("no configuration base address register!\n");
     43		return -ENXIO;
     44	}
     45
     46	/* Config base address register value is zero for uniprocessor */
     47	config_base = scu_a9_get_base();
     48	if (!config_base) {
     49		pr_err("hardware reports only one core\n");
     50		return -ENOENT;
     51	}
     52
     53	scu_base = ioremap((phys_addr_t)config_base, CORTEX_A9_SCU_SIZE);
     54	if (!scu_base) {
     55		pr_err("failed to remap config base (%lu/%u) for SCU\n",
     56			config_base, CORTEX_A9_SCU_SIZE);
     57		return -ENOMEM;
     58	}
     59
     60	scu_enable(scu_base);
     61
     62	ncores = scu_base ? scu_get_core_count(scu_base) : 1;
     63
     64	if (ncores > nr_cpu_ids) {
     65		pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
     66				ncores, nr_cpu_ids);
     67		ncores = nr_cpu_ids;
     68	}
     69
     70	/* The BCM63138 SoC has two Cortex-A9 CPUs, CPU0 features a complete
     71	 * and fully functional VFP unit that can be used, but CPU1 does not.
     72	 * Since we will not be able to trap kernel-mode NEON to force
     73	 * migration to CPU0, just do not advertise VFP support at all.
     74	 *
     75	 * This will make vfp_init bail out and do not attempt to use VFP at
     76	 * all, for kernel-mode NEON, we do not want to introduce any
     77	 * conditionals in hot-paths, so we just restrict the system to UP.
     78	 */
     79#ifdef CONFIG_VFP
     80	if (ncores > 1) {
     81		pr_warn("SMP: secondary CPUs lack VFP unit, disabling VFP\n");
     82		vfp_disable();
     83
     84#ifdef CONFIG_KERNEL_MODE_NEON
     85		WARN(1, "SMP: kernel-mode NEON enabled, restricting to UP\n");
     86		ncores = 1;
     87#endif
     88	}
     89#endif
     90
     91	for (i = 0; i < ncores; i++)
     92		set_cpu_possible(i, true);
     93
     94	iounmap(scu_base);	/* That's the last we'll need of this */
     95
     96	return 0;
     97}
     98
     99static const struct of_device_id bcm63138_bootlut_ids[] = {
    100	{ .compatible = "brcm,bcm63138-bootlut", },
    101	{ /* sentinel */ },
    102};
    103
    104#define BOOTLUT_RESET_VECT	0x20
    105
    106static int bcm63138_smp_boot_secondary(unsigned int cpu,
    107				       struct task_struct *idle)
    108{
    109	void __iomem *bootlut_base;
    110	struct device_node *dn;
    111	int ret = 0;
    112	u32 val;
    113
    114	dn = of_find_matching_node(NULL, bcm63138_bootlut_ids);
    115	if (!dn) {
    116		pr_err("SMP: unable to find bcm63138 boot LUT node\n");
    117		return -ENODEV;
    118	}
    119
    120	bootlut_base = of_iomap(dn, 0);
    121	of_node_put(dn);
    122
    123	if (!bootlut_base) {
    124		pr_err("SMP: unable to remap boot LUT base register\n");
    125		return -ENOMEM;
    126	}
    127
    128	/* Locate the secondary CPU node */
    129	dn = of_get_cpu_node(cpu, NULL);
    130	if (!dn) {
    131		pr_err("SMP: failed to locate secondary CPU%d node\n", cpu);
    132		ret = -ENODEV;
    133		goto out;
    134	}
    135
    136	/* Write the secondary init routine to the BootLUT reset vector */
    137	val = __pa_symbol(secondary_startup);
    138	writel_relaxed(val, bootlut_base + BOOTLUT_RESET_VECT);
    139
    140	/* Power up the core, will jump straight to its reset vector when we
    141	 * return
    142	 */
    143	ret = bcm63xx_pmb_power_on_cpu(dn);
    144	of_node_put(dn);
    145	if (ret)
    146		goto out;
    147out:
    148	iounmap(bootlut_base);
    149
    150	return ret;
    151}
    152
    153static void __init bcm63138_smp_prepare_cpus(unsigned int max_cpus)
    154{
    155	int ret;
    156
    157	ret = scu_a9_enable();
    158	if (ret) {
    159		pr_warn("SMP: Cortex-A9 SCU setup failed\n");
    160		return;
    161	}
    162}
    163
    164static const struct smp_operations bcm63138_smp_ops __initconst = {
    165	.smp_prepare_cpus	= bcm63138_smp_prepare_cpus,
    166	.smp_boot_secondary	= bcm63138_smp_boot_secondary,
    167};
    168
    169CPU_METHOD_OF_DECLARE(bcm63138_smp, "brcm,bcm63138", &bcm63138_smp_ops);