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 (2922B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 *  Copyright (C) 2002 ARM Ltd.
      4 *  All Rights Reserved
      5 *
      6 * This code is specific to the hardware found on ARM Realview and
      7 * Versatile Express platforms where the CPUs are unable to be individually
      8 * woken, and where there is no way to hot-unplug CPUs.  Real platforms
      9 * should not copy this code.
     10 */
     11#include <linux/init.h>
     12#include <linux/errno.h>
     13#include <linux/delay.h>
     14#include <linux/device.h>
     15#include <linux/jiffies.h>
     16#include <linux/smp.h>
     17
     18#include <asm/cacheflush.h>
     19#include <asm/smp_plat.h>
     20
     21#include "platsmp.h"
     22
     23/*
     24 * versatile_cpu_release controls the release of CPUs from the holding
     25 * pen in headsmp.S, which exists because we are not always able to
     26 * control the release of individual CPUs from the board firmware.
     27 * Production platforms do not need this.
     28 */
     29volatile int versatile_cpu_release = -1;
     30
     31/*
     32 * Write versatile_cpu_release in a way that is guaranteed to be visible to
     33 * all observers, irrespective of whether they're taking part in coherency
     34 * or not.  This is necessary for the hotplug code to work reliably.
     35 */
     36static void versatile_write_cpu_release(int val)
     37{
     38	versatile_cpu_release = val;
     39	smp_wmb();
     40	sync_cache_w(&versatile_cpu_release);
     41}
     42
     43/*
     44 * versatile_lock exists to avoid running the loops_per_jiffy delay loop
     45 * calibrations on the secondary CPU while the requesting CPU is using
     46 * the limited-bandwidth bus - which affects the calibration value.
     47 * Production platforms do not need this.
     48 */
     49static DEFINE_RAW_SPINLOCK(versatile_lock);
     50
     51void versatile_secondary_init(unsigned int cpu)
     52{
     53	/*
     54	 * let the primary processor know we're out of the
     55	 * pen, then head off into the C entry point
     56	 */
     57	versatile_write_cpu_release(-1);
     58
     59	/*
     60	 * Synchronise with the boot thread.
     61	 */
     62	raw_spin_lock(&versatile_lock);
     63	raw_spin_unlock(&versatile_lock);
     64}
     65
     66int versatile_boot_secondary(unsigned int cpu, struct task_struct *idle)
     67{
     68	unsigned long timeout;
     69
     70	/*
     71	 * Set synchronisation state between this boot processor
     72	 * and the secondary one
     73	 */
     74	raw_spin_lock(&versatile_lock);
     75
     76	/*
     77	 * This is really belt and braces; we hold unintended secondary
     78	 * CPUs in the holding pen until we're ready for them.  However,
     79	 * since we haven't sent them a soft interrupt, they shouldn't
     80	 * be there.
     81	 */
     82	versatile_write_cpu_release(cpu_logical_map(cpu));
     83
     84	/*
     85	 * Send the secondary CPU a soft interrupt, thereby causing
     86	 * the boot monitor to read the system wide flags register,
     87	 * and branch to the address found there.
     88	 */
     89	arch_send_wakeup_ipi_mask(cpumask_of(cpu));
     90
     91	timeout = jiffies + (1 * HZ);
     92	while (time_before(jiffies, timeout)) {
     93		smp_rmb();
     94		if (versatile_cpu_release == -1)
     95			break;
     96
     97		udelay(10);
     98	}
     99
    100	/*
    101	 * now the secondary core is starting up let it run its
    102	 * calibrations, then wait for it to finish
    103	 */
    104	raw_spin_unlock(&versatile_lock);
    105
    106	return versatile_cpu_release != -1 ? -ENOSYS : 0;
    107}