Path: blob/master/arch/sh/kernel/cpu/sh4a/smp-shx3.c
17621 views
/*1* SH-X3 SMP2*3* Copyright (C) 2007 - 2010 Paul Mundt4* Copyright (C) 2007 Magnus Damm5*6* This file is subject to the terms and conditions of the GNU General Public7* License. See the file "COPYING" in the main directory of this archive8* for more details.9*/10#include <linux/init.h>11#include <linux/kernel.h>12#include <linux/cpumask.h>13#include <linux/smp.h>14#include <linux/interrupt.h>15#include <linux/io.h>16#include <linux/sched.h>17#include <linux/delay.h>18#include <linux/cpu.h>19#include <asm/sections.h>2021#define STBCR_REG(phys_id) (0xfe400004 | (phys_id << 12))22#define RESET_REG(phys_id) (0xfe400008 | (phys_id << 12))2324#define STBCR_MSTP 0x0000000125#define STBCR_RESET 0x0000000226#define STBCR_SLEEP 0x0000000427#define STBCR_LTSLP 0x800000002829static irqreturn_t ipi_interrupt_handler(int irq, void *arg)30{31unsigned int message = (unsigned int)(long)arg;32unsigned int cpu = hard_smp_processor_id();33unsigned int offs = 4 * cpu;34unsigned int x;3536x = __raw_readl(0xfe410070 + offs); /* C0INITICI..CnINTICI */37x &= (1 << (message << 2));38__raw_writel(x, 0xfe410080 + offs); /* C0INTICICLR..CnINTICICLR */3940smp_message_recv(message);4142return IRQ_HANDLED;43}4445static void shx3_smp_setup(void)46{47unsigned int cpu = 0;48int i, num;4950init_cpu_possible(cpumask_of(cpu));5152/* Enable light sleep for the boot CPU */53__raw_writel(__raw_readl(STBCR_REG(cpu)) | STBCR_LTSLP, STBCR_REG(cpu));5455__cpu_number_map[0] = 0;56__cpu_logical_map[0] = 0;5758/*59* Do this stupidly for now.. we don't have an easy way to probe60* for the total number of cores.61*/62for (i = 1, num = 0; i < NR_CPUS; i++) {63set_cpu_possible(i, true);64__cpu_number_map[i] = ++num;65__cpu_logical_map[num] = i;66}6768printk(KERN_INFO "Detected %i available secondary CPU(s)\n", num);69}7071static void shx3_prepare_cpus(unsigned int max_cpus)72{73int i;7475local_timer_setup(0);7677BUILD_BUG_ON(SMP_MSG_NR >= 8);7879for (i = 0; i < SMP_MSG_NR; i++)80request_irq(104 + i, ipi_interrupt_handler,81IRQF_DISABLED | IRQF_PERCPU, "IPI", (void *)(long)i);8283for (i = 0; i < max_cpus; i++)84set_cpu_present(i, true);85}8687static void shx3_start_cpu(unsigned int cpu, unsigned long entry_point)88{89if (__in_29bit_mode())90__raw_writel(entry_point, RESET_REG(cpu));91else92__raw_writel(virt_to_phys(entry_point), RESET_REG(cpu));9394if (!(__raw_readl(STBCR_REG(cpu)) & STBCR_MSTP))95__raw_writel(STBCR_MSTP, STBCR_REG(cpu));9697while (!(__raw_readl(STBCR_REG(cpu)) & STBCR_MSTP))98cpu_relax();99100/* Start up secondary processor by sending a reset */101__raw_writel(STBCR_RESET | STBCR_LTSLP, STBCR_REG(cpu));102}103104static unsigned int shx3_smp_processor_id(void)105{106return __raw_readl(0xff000048); /* CPIDR */107}108109static void shx3_send_ipi(unsigned int cpu, unsigned int message)110{111unsigned long addr = 0xfe410070 + (cpu * 4);112113BUG_ON(cpu >= 4);114115__raw_writel(1 << (message << 2), addr); /* C0INTICI..CnINTICI */116}117118static void shx3_update_boot_vector(unsigned int cpu)119{120__raw_writel(STBCR_MSTP, STBCR_REG(cpu));121while (!(__raw_readl(STBCR_REG(cpu)) & STBCR_MSTP))122cpu_relax();123__raw_writel(STBCR_RESET, STBCR_REG(cpu));124}125126static int __cpuinit127shx3_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)128{129unsigned int cpu = (unsigned int)hcpu;130131switch (action) {132case CPU_UP_PREPARE:133shx3_update_boot_vector(cpu);134break;135case CPU_ONLINE:136pr_info("CPU %u is now online\n", cpu);137break;138case CPU_DEAD:139break;140}141142return NOTIFY_OK;143}144145static struct notifier_block __cpuinitdata shx3_cpu_notifier = {146.notifier_call = shx3_cpu_callback,147};148149static int __cpuinit register_shx3_cpu_notifier(void)150{151register_hotcpu_notifier(&shx3_cpu_notifier);152return 0;153}154late_initcall(register_shx3_cpu_notifier);155156struct plat_smp_ops shx3_smp_ops = {157.smp_setup = shx3_smp_setup,158.prepare_cpus = shx3_prepare_cpus,159.start_cpu = shx3_start_cpu,160.smp_processor_id = shx3_smp_processor_id,161.send_ipi = shx3_send_ipi,162.cpu_die = native_cpu_die,163.cpu_disable = native_cpu_disable,164.play_dead = native_play_dead,165};166167168