linux/arch/arm/common/mcpm_platsmp.c
<<
>>
Prefs
   1/*
   2 * linux/arch/arm/mach-vexpress/mcpm_platsmp.c
   3 *
   4 * Created by:  Nicolas Pitre, November 2012
   5 * Copyright:   (C) 2012-2013  Linaro Limited
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 *
  11 * Code to handle secondary CPU bringup and hotplug for the cluster power API.
  12 */
  13
  14#include <linux/init.h>
  15#include <linux/smp.h>
  16#include <linux/spinlock.h>
  17
  18#include <asm/mcpm.h>
  19#include <asm/smp.h>
  20#include <asm/smp_plat.h>
  21
  22static void cpu_to_pcpu(unsigned int cpu,
  23                        unsigned int *pcpu, unsigned int *pcluster)
  24{
  25        unsigned int mpidr;
  26
  27        mpidr = cpu_logical_map(cpu);
  28        *pcpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
  29        *pcluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
  30}
  31
  32static int mcpm_boot_secondary(unsigned int cpu, struct task_struct *idle)
  33{
  34        unsigned int pcpu, pcluster, ret;
  35        extern void secondary_startup(void);
  36
  37        cpu_to_pcpu(cpu, &pcpu, &pcluster);
  38
  39        pr_debug("%s: logical CPU %d is physical CPU %d cluster %d\n",
  40                 __func__, cpu, pcpu, pcluster);
  41
  42        mcpm_set_entry_vector(pcpu, pcluster, NULL);
  43        ret = mcpm_cpu_power_up(pcpu, pcluster);
  44        if (ret)
  45                return ret;
  46        mcpm_set_entry_vector(pcpu, pcluster, secondary_startup);
  47        arch_send_wakeup_ipi_mask(cpumask_of(cpu));
  48        dsb_sev();
  49        return 0;
  50}
  51
  52static void mcpm_secondary_init(unsigned int cpu)
  53{
  54        mcpm_cpu_powered_up();
  55}
  56
  57#ifdef CONFIG_HOTPLUG_CPU
  58
  59static int mcpm_cpu_kill(unsigned int cpu)
  60{
  61        unsigned int pcpu, pcluster;
  62
  63        cpu_to_pcpu(cpu, &pcpu, &pcluster);
  64
  65        return !mcpm_wait_for_cpu_powerdown(pcpu, pcluster);
  66}
  67
  68static bool mcpm_cpu_can_disable(unsigned int cpu)
  69{
  70        /* We assume all CPUs may be shut down. */
  71        return true;
  72}
  73
  74static void mcpm_cpu_die(unsigned int cpu)
  75{
  76        unsigned int mpidr, pcpu, pcluster;
  77        mpidr = read_cpuid_mpidr();
  78        pcpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
  79        pcluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
  80        mcpm_set_entry_vector(pcpu, pcluster, NULL);
  81        mcpm_cpu_power_down();
  82}
  83
  84#endif
  85
  86static const struct smp_operations mcpm_smp_ops __initconst = {
  87        .smp_boot_secondary     = mcpm_boot_secondary,
  88        .smp_secondary_init     = mcpm_secondary_init,
  89#ifdef CONFIG_HOTPLUG_CPU
  90        .cpu_kill               = mcpm_cpu_kill,
  91        .cpu_can_disable        = mcpm_cpu_can_disable,
  92        .cpu_die                = mcpm_cpu_die,
  93#endif
  94};
  95
  96void __init mcpm_smp_set_ops(void)
  97{
  98        smp_set_ops(&mcpm_smp_ops);
  99}
 100