16b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang/*
296f1050d3df105c9ae6c6ac224f370199ea82fcdRobin Getz * IPI management based on arch/arm/kernel/smp.c (Copyright 2002 ARM Limited)
36b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang *
496f1050d3df105c9ae6c6ac224f370199ea82fcdRobin Getz * Copyright 2007-2009 Analog Devices Inc.
596f1050d3df105c9ae6c6ac224f370199ea82fcdRobin Getz *                         Philippe Gerum <rpm@xenomai.org>
66b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang *
796f1050d3df105c9ae6c6ac224f370199ea82fcdRobin Getz * Licensed under the GPL-2.
86b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang */
96b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
106b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang#include <linux/module.h>
116b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang#include <linux/delay.h>
126b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang#include <linux/init.h>
136b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang#include <linux/spinlock.h>
146b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang#include <linux/sched.h>
156b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang#include <linux/interrupt.h>
166b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang#include <linux/cache.h>
17d0014be47dc90d15adf7d6e09031d06e2aa7ce79Bob Liu#include <linux/clockchips.h>
186b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang#include <linux/profile.h>
196b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang#include <linux/errno.h>
206b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang#include <linux/mm.h>
216b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang#include <linux/cpu.h>
226b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang#include <linux/smp.h>
239c199b5965c76f90b297e01accb933624dc8d242Graf Yang#include <linux/cpumask.h>
246b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang#include <linux/seq_file.h>
256b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang#include <linux/irq.h>
265a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
2760063497a95e716c9a689af3be2687d261f115b4Arun Sharma#include <linux/atomic.h>
286b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang#include <asm/cacheflush.h>
296327a574f9ce85f0daab8693913003a456f27f1fMike Frysinger#include <asm/irq_handler.h>
306b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang#include <asm/mmu_context.h>
316b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang#include <asm/pgtable.h>
326b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang#include <asm/pgalloc.h>
336b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang#include <asm/processor.h>
346b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang#include <asm/ptrace.h>
356b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang#include <asm/cpu.h>
361fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang#include <asm/time.h>
376b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang#include <linux/err.h>
386b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
39555487bbb63f527e63fecbff48c86e2c07ce5024Graf Yang/*
40555487bbb63f527e63fecbff48c86e2c07ce5024Graf Yang * Anomaly notes:
41555487bbb63f527e63fecbff48c86e2c07ce5024Graf Yang * 05000120 - we always define corelock as 32-bit integer in L2
42555487bbb63f527e63fecbff48c86e2c07ce5024Graf Yang */
436b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yangstruct corelock_slot corelock __attribute__ ((__section__(".l2.bss")));
446b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
45c6345ab1a3d17f4b6c80ac79d7fb0f006b32fdaaSonic Zhang#ifdef CONFIG_ICACHE_FLUSH_L1
46c6345ab1a3d17f4b6c80ac79d7fb0f006b32fdaaSonic Zhangunsigned long blackfin_iflush_l1_entry[NR_CPUS];
47c6345ab1a3d17f4b6c80ac79d7fb0f006b32fdaaSonic Zhang#endif
48c6345ab1a3d17f4b6c80ac79d7fb0f006b32fdaaSonic Zhang
4913dff62d80e93f1cc65b4ad2dddedd12de720272Paul Gortmakerstruct blackfin_initial_pda initial_pda_coreb;
506b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
5150888469bda11bcff306893bbaff21f25894be0bSteven Miaoenum ipi_message_type {
52150382a53d11256e5666c86525c8bf8d23684532Steven Miao	BFIN_IPI_NONE,
5350888469bda11bcff306893bbaff21f25894be0bSteven Miao	BFIN_IPI_TIMER,
5450888469bda11bcff306893bbaff21f25894be0bSteven Miao	BFIN_IPI_RESCHEDULE,
5550888469bda11bcff306893bbaff21f25894be0bSteven Miao	BFIN_IPI_CALL_FUNC,
5650888469bda11bcff306893bbaff21f25894be0bSteven Miao	BFIN_IPI_CPU_STOP,
5750888469bda11bcff306893bbaff21f25894be0bSteven Miao};
586b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
596b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yangstruct blackfin_flush_data {
606b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	unsigned long start;
616b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	unsigned long end;
626b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang};
636b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
646b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yangvoid *secondary_stack;
656b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
666b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yangstatic struct blackfin_flush_data smp_flush_data;
676b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
686b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yangstatic DEFINE_SPINLOCK(stop_lock);
696b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
7073a400646b8e26615f3ef1a0a4bc0cd0d5bd284cYi Li/* A magic number - stress test shows this is safe for common cases */
7173a400646b8e26615f3ef1a0a4bc0cd0d5bd284cYi Li#define BFIN_IPI_MSGQ_LEN 5
7273a400646b8e26615f3ef1a0a4bc0cd0d5bd284cYi Li
7373a400646b8e26615f3ef1a0a4bc0cd0d5bd284cYi Li/* Simple FIFO buffer, overflow leads to panic */
7450888469bda11bcff306893bbaff21f25894be0bSteven Miaostruct ipi_data {
75150382a53d11256e5666c86525c8bf8d23684532Steven Miao	atomic_t count;
76150382a53d11256e5666c86525c8bf8d23684532Steven Miao	atomic_t bits;
776b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang};
786b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
7950888469bda11bcff306893bbaff21f25894be0bSteven Miaostatic DEFINE_PER_CPU(struct ipi_data, bfin_ipi);
806b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
816b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yangstatic void ipi_cpu_stop(unsigned int cpu)
826b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang{
836b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	spin_lock(&stop_lock);
846b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	printk(KERN_CRIT "CPU%u: stopping\n", cpu);
856b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	dump_stack();
866b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	spin_unlock(&stop_lock);
876b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
88fecedc807116ed820ca6f3138d6d47a3bc6c5a60KOSAKI Motohiro	set_cpu_online(cpu, false);
896b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
906b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	local_irq_disable();
916b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
926b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	while (1)
936b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang		SSYNC();
946b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang}
956b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
966b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yangstatic void ipi_flush_icache(void *info)
976b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang{
986b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	struct blackfin_flush_data *fdata = info;
996b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
1006b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	/* Invalidate the memory holding the bounds of the flushed region. */
1018d50de9ee77b38a239dc5b1d6a63ad92a78f119dSonic Zhang	blackfin_dcache_invalidate_range((unsigned long)fdata,
1028d50de9ee77b38a239dc5b1d6a63ad92a78f119dSonic Zhang					 (unsigned long)fdata + sizeof(*fdata));
1038d50de9ee77b38a239dc5b1d6a63ad92a78f119dSonic Zhang
1048d50de9ee77b38a239dc5b1d6a63ad92a78f119dSonic Zhang	/* Make sure all write buffers in the data side of the core
1058d50de9ee77b38a239dc5b1d6a63ad92a78f119dSonic Zhang	 * are flushed before trying to invalidate the icache.  This
1068d50de9ee77b38a239dc5b1d6a63ad92a78f119dSonic Zhang	 * needs to be after the data flush and before the icache
1078d50de9ee77b38a239dc5b1d6a63ad92a78f119dSonic Zhang	 * flush so that the SSYNC does the right thing in preventing
1088d50de9ee77b38a239dc5b1d6a63ad92a78f119dSonic Zhang	 * the instruction prefetcher from hitting things in cached
1098d50de9ee77b38a239dc5b1d6a63ad92a78f119dSonic Zhang	 * memory at the wrong time -- it runs much further ahead than
1108d50de9ee77b38a239dc5b1d6a63ad92a78f119dSonic Zhang	 * the pipeline.
1118d50de9ee77b38a239dc5b1d6a63ad92a78f119dSonic Zhang	 */
1128d50de9ee77b38a239dc5b1d6a63ad92a78f119dSonic Zhang	SSYNC();
1138d50de9ee77b38a239dc5b1d6a63ad92a78f119dSonic Zhang
1148d50de9ee77b38a239dc5b1d6a63ad92a78f119dSonic Zhang	/* ipi_flaush_icache is invoked by generic flush_icache_range,
1158d50de9ee77b38a239dc5b1d6a63ad92a78f119dSonic Zhang	 * so call blackfin arch icache flush directly here.
1168d50de9ee77b38a239dc5b1d6a63ad92a78f119dSonic Zhang	 */
1178d50de9ee77b38a239dc5b1d6a63ad92a78f119dSonic Zhang	blackfin_icache_flush_range(fdata->start, fdata->end);
1186b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang}
1196b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
12073a400646b8e26615f3ef1a0a4bc0cd0d5bd284cYi Li/* Use IRQ_SUPPLE_0 to request reschedule.
12173a400646b8e26615f3ef1a0a4bc0cd0d5bd284cYi Li * When returning from interrupt to user space,
12273a400646b8e26615f3ef1a0a4bc0cd0d5bd284cYi Li * there is chance to reschedule */
12373a400646b8e26615f3ef1a0a4bc0cd0d5bd284cYi Listatic irqreturn_t ipi_handler_int0(int irq, void *dev_instance)
12473a400646b8e26615f3ef1a0a4bc0cd0d5bd284cYi Li{
12573a400646b8e26615f3ef1a0a4bc0cd0d5bd284cYi Li	unsigned int cpu = smp_processor_id();
12673a400646b8e26615f3ef1a0a4bc0cd0d5bd284cYi Li
12773a400646b8e26615f3ef1a0a4bc0cd0d5bd284cYi Li	platform_clear_ipi(cpu, IRQ_SUPPLE_0);
12873a400646b8e26615f3ef1a0a4bc0cd0d5bd284cYi Li	return IRQ_HANDLED;
12973a400646b8e26615f3ef1a0a4bc0cd0d5bd284cYi Li}
13073a400646b8e26615f3ef1a0a4bc0cd0d5bd284cYi Li
131d0014be47dc90d15adf7d6e09031d06e2aa7ce79Bob LiuDECLARE_PER_CPU(struct clock_event_device, coretmr_events);
132d0014be47dc90d15adf7d6e09031d06e2aa7ce79Bob Liuvoid ipi_timer(void)
133d0014be47dc90d15adf7d6e09031d06e2aa7ce79Bob Liu{
134d0014be47dc90d15adf7d6e09031d06e2aa7ce79Bob Liu	int cpu = smp_processor_id();
135d0014be47dc90d15adf7d6e09031d06e2aa7ce79Bob Liu	struct clock_event_device *evt = &per_cpu(coretmr_events, cpu);
136d0014be47dc90d15adf7d6e09031d06e2aa7ce79Bob Liu	evt->event_handler(evt);
137d0014be47dc90d15adf7d6e09031d06e2aa7ce79Bob Liu}
138d0014be47dc90d15adf7d6e09031d06e2aa7ce79Bob Liu
13973a400646b8e26615f3ef1a0a4bc0cd0d5bd284cYi Listatic irqreturn_t ipi_handler_int1(int irq, void *dev_instance)
1406b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang{
14150888469bda11bcff306893bbaff21f25894be0bSteven Miao	struct ipi_data *bfin_ipi_data;
1426b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	unsigned int cpu = smp_processor_id();
14350888469bda11bcff306893bbaff21f25894be0bSteven Miao	unsigned long pending;
14450888469bda11bcff306893bbaff21f25894be0bSteven Miao	unsigned long msg;
1456b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
14673a400646b8e26615f3ef1a0a4bc0cd0d5bd284cYi Li	platform_clear_ipi(cpu, IRQ_SUPPLE_1);
1476b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
148177a48fdc8a0156b32f96d9d0056361d88203983Steven Miao	smp_rmb();
1497e788ab11d73fbb617973c12a9b3f84f93721e67Christoph Lameter	bfin_ipi_data = this_cpu_ptr(&bfin_ipi);
15016fc5bc4c76b9ac335c2b39943f29c5d047a822dSteven Miao	while ((pending = atomic_xchg(&bfin_ipi_data->bits, 0)) != 0) {
15150888469bda11bcff306893bbaff21f25894be0bSteven Miao		msg = 0;
15250888469bda11bcff306893bbaff21f25894be0bSteven Miao		do {
15350888469bda11bcff306893bbaff21f25894be0bSteven Miao			msg = find_next_bit(&pending, BITS_PER_LONG, msg + 1);
15450888469bda11bcff306893bbaff21f25894be0bSteven Miao			switch (msg) {
15550888469bda11bcff306893bbaff21f25894be0bSteven Miao			case BFIN_IPI_TIMER:
15650888469bda11bcff306893bbaff21f25894be0bSteven Miao				ipi_timer();
15750888469bda11bcff306893bbaff21f25894be0bSteven Miao				break;
15850888469bda11bcff306893bbaff21f25894be0bSteven Miao			case BFIN_IPI_RESCHEDULE:
15950888469bda11bcff306893bbaff21f25894be0bSteven Miao				scheduler_ipi();
16050888469bda11bcff306893bbaff21f25894be0bSteven Miao				break;
16150888469bda11bcff306893bbaff21f25894be0bSteven Miao			case BFIN_IPI_CALL_FUNC:
16250888469bda11bcff306893bbaff21f25894be0bSteven Miao				generic_smp_call_function_interrupt();
16350888469bda11bcff306893bbaff21f25894be0bSteven Miao				break;
16450888469bda11bcff306893bbaff21f25894be0bSteven Miao			case BFIN_IPI_CPU_STOP:
16550888469bda11bcff306893bbaff21f25894be0bSteven Miao				ipi_cpu_stop(cpu);
16650888469bda11bcff306893bbaff21f25894be0bSteven Miao				break;
167177a48fdc8a0156b32f96d9d0056361d88203983Steven Miao			default:
168177a48fdc8a0156b32f96d9d0056361d88203983Steven Miao				goto out;
16950888469bda11bcff306893bbaff21f25894be0bSteven Miao			}
170150382a53d11256e5666c86525c8bf8d23684532Steven Miao			atomic_dec(&bfin_ipi_data->count);
17150888469bda11bcff306893bbaff21f25894be0bSteven Miao		} while (msg < BITS_PER_LONG);
172177a48fdc8a0156b32f96d9d0056361d88203983Steven Miao
1736b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	}
174177a48fdc8a0156b32f96d9d0056361d88203983Steven Miaoout:
1756b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	return IRQ_HANDLED;
1766b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang}
1776b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
17850888469bda11bcff306893bbaff21f25894be0bSteven Miaostatic void bfin_ipi_init(void)
1796b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang{
1806b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	unsigned int cpu;
18150888469bda11bcff306893bbaff21f25894be0bSteven Miao	struct ipi_data *bfin_ipi_data;
1826b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	for_each_possible_cpu(cpu) {
18350888469bda11bcff306893bbaff21f25894be0bSteven Miao		bfin_ipi_data = &per_cpu(bfin_ipi, cpu);
18416fc5bc4c76b9ac335c2b39943f29c5d047a822dSteven Miao		atomic_set(&bfin_ipi_data->bits, 0);
18516fc5bc4c76b9ac335c2b39943f29c5d047a822dSteven Miao		atomic_set(&bfin_ipi_data->count, 0);
1866b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	}
1876b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang}
1886b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
18950888469bda11bcff306893bbaff21f25894be0bSteven Miaovoid send_ipi(const struct cpumask *cpumask, enum ipi_message_type msg)
1906b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang{
1916b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	unsigned int cpu;
19250888469bda11bcff306893bbaff21f25894be0bSteven Miao	struct ipi_data *bfin_ipi_data;
19350888469bda11bcff306893bbaff21f25894be0bSteven Miao	unsigned long flags;
19450888469bda11bcff306893bbaff21f25894be0bSteven Miao
19550888469bda11bcff306893bbaff21f25894be0bSteven Miao	local_irq_save(flags);
19650888469bda11bcff306893bbaff21f25894be0bSteven Miao	for_each_cpu(cpu, cpumask) {
19750888469bda11bcff306893bbaff21f25894be0bSteven Miao		bfin_ipi_data = &per_cpu(bfin_ipi, cpu);
198150382a53d11256e5666c86525c8bf8d23684532Steven Miao		atomic_set_mask((1 << msg), &bfin_ipi_data->bits);
199150382a53d11256e5666c86525c8bf8d23684532Steven Miao		atomic_inc(&bfin_ipi_data->count);
2006b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	}
20150888469bda11bcff306893bbaff21f25894be0bSteven Miao	local_irq_restore(flags);
202177a48fdc8a0156b32f96d9d0056361d88203983Steven Miao	smp_wmb();
203177a48fdc8a0156b32f96d9d0056361d88203983Steven Miao	for_each_cpu(cpu, cpumask)
204177a48fdc8a0156b32f96d9d0056361d88203983Steven Miao		platform_send_ipi_cpu(cpu, IRQ_SUPPLE_1);
20573a400646b8e26615f3ef1a0a4bc0cd0d5bd284cYi Li}
20673a400646b8e26615f3ef1a0a4bc0cd0d5bd284cYi Li
20750888469bda11bcff306893bbaff21f25894be0bSteven Miaovoid arch_send_call_function_single_ipi(int cpu)
20873a400646b8e26615f3ef1a0a4bc0cd0d5bd284cYi Li{
2095e98c0990471fa1ee707f5c3a6f5183355b19828Jiang Liu	send_ipi(cpumask_of(cpu), BFIN_IPI_CALL_FUNC);
2106b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang}
2116b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
21250888469bda11bcff306893bbaff21f25894be0bSteven Miaovoid arch_send_call_function_ipi_mask(const struct cpumask *mask)
2136b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang{
21450888469bda11bcff306893bbaff21f25894be0bSteven Miao	send_ipi(mask, BFIN_IPI_CALL_FUNC);
2156b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang}
2166b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
2176b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yangvoid smp_send_reschedule(int cpu)
2186b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang{
21950888469bda11bcff306893bbaff21f25894be0bSteven Miao	send_ipi(cpumask_of(cpu), BFIN_IPI_RESCHEDULE);
2206b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
2216b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	return;
2226b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang}
2236b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
224d0014be47dc90d15adf7d6e09031d06e2aa7ce79Bob Liuvoid smp_send_msg(const struct cpumask *mask, unsigned long type)
225d0014be47dc90d15adf7d6e09031d06e2aa7ce79Bob Liu{
22650888469bda11bcff306893bbaff21f25894be0bSteven Miao	send_ipi(mask, type);
227d0014be47dc90d15adf7d6e09031d06e2aa7ce79Bob Liu}
228d0014be47dc90d15adf7d6e09031d06e2aa7ce79Bob Liu
229d0014be47dc90d15adf7d6e09031d06e2aa7ce79Bob Liuvoid smp_timer_broadcast(const struct cpumask *mask)
230d0014be47dc90d15adf7d6e09031d06e2aa7ce79Bob Liu{
231d0014be47dc90d15adf7d6e09031d06e2aa7ce79Bob Liu	smp_send_msg(mask, BFIN_IPI_TIMER);
232d0014be47dc90d15adf7d6e09031d06e2aa7ce79Bob Liu}
233d0014be47dc90d15adf7d6e09031d06e2aa7ce79Bob Liu
2346b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yangvoid smp_send_stop(void)
2356b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang{
2366b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	cpumask_t callmap;
2376b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
238567ebfc99d7546913408b560ad443a5315bf8a53Sonic Zhang	preempt_disable();
239fecedc807116ed820ca6f3138d6d47a3bc6c5a60KOSAKI Motohiro	cpumask_copy(&callmap, cpu_online_mask);
240fecedc807116ed820ca6f3138d6d47a3bc6c5a60KOSAKI Motohiro	cpumask_clear_cpu(smp_processor_id(), &callmap);
241fecedc807116ed820ca6f3138d6d47a3bc6c5a60KOSAKI Motohiro	if (!cpumask_empty(&callmap))
24250888469bda11bcff306893bbaff21f25894be0bSteven Miao		send_ipi(&callmap, BFIN_IPI_CPU_STOP);
2436b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
244567ebfc99d7546913408b560ad443a5315bf8a53Sonic Zhang	preempt_enable();
2456b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
2466b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	return;
2476b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang}
2486b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
24913dff62d80e93f1cc65b4ad2dddedd12de720272Paul Gortmakerint __cpu_up(unsigned int cpu, struct task_struct *idle)
2506b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang{
2516b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	int ret;
2520b39db28b953945232719e7ff6fb802aa8a2be5fGraf Yang
2536b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	secondary_stack = task_stack_page(idle) + THREAD_SIZE;
2546b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
2556b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	ret = platform_boot_secondary(cpu, idle);
2566b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
2576b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	secondary_stack = NULL;
2586b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
2596b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	return ret;
2606b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang}
2616b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
26213dff62d80e93f1cc65b4ad2dddedd12de720272Paul Gortmakerstatic void setup_secondary(unsigned int cpu)
2636b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang{
2646b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	unsigned long ilat;
2656b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
2666b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	bfin_write_IMASK(0);
2676b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	CSYNC();
2686b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	ilat = bfin_read_ILAT();
2696b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	CSYNC();
2706b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	bfin_write_ILAT(ilat);
2716b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	CSYNC();
2726b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
2736b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	/* Enable interrupt levels IVG7-15. IARs have been already
2746b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	 * programmed by the boot CPU.  */
275400597842452c02916a61a51f3154dd032c2d569Mike Frysinger	bfin_irq_flags |= IMASK_IVG15 |
2766b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	    IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 |
2776b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	    IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW;
2786b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang}
2796b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
28013dff62d80e93f1cc65b4ad2dddedd12de720272Paul Gortmakervoid secondary_start_kernel(void)
2816b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang{
2826b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	unsigned int cpu = smp_processor_id();
2836b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	struct mm_struct *mm = &init_mm;
2846b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
2856b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	if (_bfin_swrst & SWRST_DBL_FAULT_B) {
2866b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang		printk(KERN_EMERG "CoreB Recovering from DOUBLE FAULT event\n");
2876b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang#ifdef CONFIG_DEBUG_DOUBLEFAULT
288fb1d9be5967fff0a3c93b06304fd992e3c438b7fMike Frysinger		printk(KERN_EMERG " While handling exception (EXCAUSE = %#x) at %pF\n",
289fb1d9be5967fff0a3c93b06304fd992e3c438b7fMike Frysinger			initial_pda_coreb.seqstat_doublefault & SEQSTAT_EXCAUSE,
290fb1d9be5967fff0a3c93b06304fd992e3c438b7fMike Frysinger			initial_pda_coreb.retx_doublefault);
291fb1d9be5967fff0a3c93b06304fd992e3c438b7fMike Frysinger		printk(KERN_NOTICE "   DCPLB_FAULT_ADDR: %pF\n",
292fb1d9be5967fff0a3c93b06304fd992e3c438b7fMike Frysinger			initial_pda_coreb.dcplb_doublefault_addr);
293fb1d9be5967fff0a3c93b06304fd992e3c438b7fMike Frysinger		printk(KERN_NOTICE "   ICPLB_FAULT_ADDR: %pF\n",
294fb1d9be5967fff0a3c93b06304fd992e3c438b7fMike Frysinger			initial_pda_coreb.icplb_doublefault_addr);
2956b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang#endif
2966b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang		printk(KERN_NOTICE " The instruction at %pF caused a double exception\n",
297fb1d9be5967fff0a3c93b06304fd992e3c438b7fMike Frysinger			initial_pda_coreb.retx);
2986b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	}
2996b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
3006b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	/*
3016b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	 * We want the D-cache to be enabled early, in case the atomic
3026b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	 * support code emulates cache coherence (see
3036b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	 * __ARCH_SYNC_CORE_DCACHE).
3046b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	 */
3056b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	init_exception_vectors();
3066b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
3076b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	local_irq_disable();
3086b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
3096b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	/* Attach the new idle task to the global mm. */
3106b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	atomic_inc(&mm->mm_users);
3116b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	atomic_inc(&mm->mm_count);
3126b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	current->active_mm = mm;
3136b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
3146b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	preempt_disable();
3156b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
3166b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	setup_secondary(cpu);
3176b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
318578d36f5e160208821e8f51037ac1038e065ecafYi Li	platform_secondary_init(cpu);
3190d152c27e336b5fd777da7dd3e814617e7305afdYi Li	/* setup local core timer */
3200d152c27e336b5fd777da7dd3e814617e7305afdYi Li	bfin_local_timer_setup();
3210d152c27e336b5fd777da7dd3e814617e7305afdYi Li
3226b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	local_irq_enable();
3236b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
324ab61d2ac5c9d7c9232b8455c8d889216ca9d4814steven miao	bfin_setup_caches(cpu);
325ab61d2ac5c9d7c9232b8455c8d889216ca9d4814steven miao
326d0014be47dc90d15adf7d6e09031d06e2aa7ce79Bob Liu	notify_cpu_starting(cpu);
327578d36f5e160208821e8f51037ac1038e065ecafYi Li	/*
328578d36f5e160208821e8f51037ac1038e065ecafYi Li	 * Calibrate loops per jiffy value.
329578d36f5e160208821e8f51037ac1038e065ecafYi Li	 * IRQs need to be enabled here - D-cache can be invalidated
330578d36f5e160208821e8f51037ac1038e065ecafYi Li	 * in timer irq handler, so core B can read correct jiffies.
331578d36f5e160208821e8f51037ac1038e065ecafYi Li	 */
332578d36f5e160208821e8f51037ac1038e065ecafYi Li	calibrate_delay();
3336b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
334150382a53d11256e5666c86525c8bf8d23684532Steven Miao	/* We are done with local CPU inits, unblock the boot CPU. */
335150382a53d11256e5666c86525c8bf8d23684532Steven Miao	set_cpu_online(cpu, true);
33625d67f860f3a29d216f8206092a284cacbc6127eThomas Gleixner	cpu_startup_entry(CPUHP_ONLINE);
3376b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang}
3386b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
3396b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yangvoid __init smp_prepare_boot_cpu(void)
3406b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang{
3416b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang}
3426b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
3436b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yangvoid __init smp_prepare_cpus(unsigned int max_cpus)
3446b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang{
3456b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	platform_prepare_cpus(max_cpus);
34650888469bda11bcff306893bbaff21f25894be0bSteven Miao	bfin_ipi_init();
34773a400646b8e26615f3ef1a0a4bc0cd0d5bd284cYi Li	platform_request_ipi(IRQ_SUPPLE_0, ipi_handler_int0);
34873a400646b8e26615f3ef1a0a4bc0cd0d5bd284cYi Li	platform_request_ipi(IRQ_SUPPLE_1, ipi_handler_int1);
3496b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang}
3506b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
3516b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yangvoid __init smp_cpus_done(unsigned int max_cpus)
3526b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang{
3536b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	unsigned long bogosum = 0;
3546b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	unsigned int cpu;
3556b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
3566b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	for_each_online_cpu(cpu)
357c70c754ff916cedd969a73549799d2167ffefcd6Michael Hennerich		bogosum += loops_per_jiffy;
3586b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
3596b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	printk(KERN_INFO "SMP: Total of %d processors activated "
3606b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	       "(%lu.%02lu BogoMIPS).\n",
3616b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	       num_online_cpus(),
3626b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	       bogosum / (500000/HZ),
3636b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	       (bogosum / (5000/HZ)) % 100);
3646b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang}
3656b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
3666b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yangvoid smp_icache_flush_range_others(unsigned long start, unsigned long end)
3676b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang{
3686b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	smp_flush_data.start = start;
3696b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	smp_flush_data.end = end;
3706b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
371a2eff9dd8bca6d03bc3c87790bac3fdb4fe6dbf0Steven Miao	preempt_disable();
372a2eff9dd8bca6d03bc3c87790bac3fdb4fe6dbf0Steven Miao	if (smp_call_function(&ipi_flush_icache, &smp_flush_data, 1))
3736b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang		printk(KERN_WARNING "SMP: failed to run I-cache flush request on other CPUs\n");
374a2eff9dd8bca6d03bc3c87790bac3fdb4fe6dbf0Steven Miao	preempt_enable();
3756b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang}
3766b3087c64a92a36ae20d33479b4df6d7afc910d4Graf YangEXPORT_SYMBOL_GPL(smp_icache_flush_range_others);
3776b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
37847e9dedb720364e0adff0e99960fa294c6161f71Sonic Zhang#ifdef __ARCH_SYNC_CORE_ICACHE
379718340f62900ed44046d2b0f74d0dec7cf844194Graf Yangunsigned long icache_invld_count[NR_CPUS];
38047e9dedb720364e0adff0e99960fa294c6161f71Sonic Zhangvoid resync_core_icache(void)
38147e9dedb720364e0adff0e99960fa294c6161f71Sonic Zhang{
38247e9dedb720364e0adff0e99960fa294c6161f71Sonic Zhang	unsigned int cpu = get_cpu();
38347e9dedb720364e0adff0e99960fa294c6161f71Sonic Zhang	blackfin_invalidate_entire_icache();
384718340f62900ed44046d2b0f74d0dec7cf844194Graf Yang	icache_invld_count[cpu]++;
38547e9dedb720364e0adff0e99960fa294c6161f71Sonic Zhang	put_cpu();
38647e9dedb720364e0adff0e99960fa294c6161f71Sonic Zhang}
38747e9dedb720364e0adff0e99960fa294c6161f71Sonic ZhangEXPORT_SYMBOL(resync_core_icache);
38847e9dedb720364e0adff0e99960fa294c6161f71Sonic Zhang#endif
38947e9dedb720364e0adff0e99960fa294c6161f71Sonic Zhang
3906b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang#ifdef __ARCH_SYNC_CORE_DCACHE
391718340f62900ed44046d2b0f74d0dec7cf844194Graf Yangunsigned long dcache_invld_count[NR_CPUS];
3926b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yangunsigned long barrier_mask __attribute__ ((__section__(".l2.bss")));
3936b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang
3946b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yangvoid resync_core_dcache(void)
3956b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang{
3966b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	unsigned int cpu = get_cpu();
3976b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	blackfin_invalidate_entire_dcache();
398718340f62900ed44046d2b0f74d0dec7cf844194Graf Yang	dcache_invld_count[cpu]++;
3996b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang	put_cpu();
4006b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang}
4016b3087c64a92a36ae20d33479b4df6d7afc910d4Graf YangEXPORT_SYMBOL(resync_core_dcache);
4026b3087c64a92a36ae20d33479b4df6d7afc910d4Graf Yang#endif
4030b39db28b953945232719e7ff6fb802aa8a2be5fGraf Yang
4040b39db28b953945232719e7ff6fb802aa8a2be5fGraf Yang#ifdef CONFIG_HOTPLUG_CPU
40513dff62d80e93f1cc65b4ad2dddedd12de720272Paul Gortmakerint __cpu_disable(void)
4060b39db28b953945232719e7ff6fb802aa8a2be5fGraf Yang{
4070b39db28b953945232719e7ff6fb802aa8a2be5fGraf Yang	unsigned int cpu = smp_processor_id();
4080b39db28b953945232719e7ff6fb802aa8a2be5fGraf Yang
4090b39db28b953945232719e7ff6fb802aa8a2be5fGraf Yang	if (cpu == 0)
4100b39db28b953945232719e7ff6fb802aa8a2be5fGraf Yang		return -EPERM;
4110b39db28b953945232719e7ff6fb802aa8a2be5fGraf Yang
4120b39db28b953945232719e7ff6fb802aa8a2be5fGraf Yang	set_cpu_online(cpu, false);
4130b39db28b953945232719e7ff6fb802aa8a2be5fGraf Yang	return 0;
4140b39db28b953945232719e7ff6fb802aa8a2be5fGraf Yang}
4150b39db28b953945232719e7ff6fb802aa8a2be5fGraf Yang
4160b39db28b953945232719e7ff6fb802aa8a2be5fGraf Yangstatic DECLARE_COMPLETION(cpu_killed);
4170b39db28b953945232719e7ff6fb802aa8a2be5fGraf Yang
41813dff62d80e93f1cc65b4ad2dddedd12de720272Paul Gortmakerint __cpu_die(unsigned int cpu)
4190b39db28b953945232719e7ff6fb802aa8a2be5fGraf Yang{
4200b39db28b953945232719e7ff6fb802aa8a2be5fGraf Yang	return wait_for_completion_timeout(&cpu_killed, 5000);
4210b39db28b953945232719e7ff6fb802aa8a2be5fGraf Yang}
4220b39db28b953945232719e7ff6fb802aa8a2be5fGraf Yang
4230b39db28b953945232719e7ff6fb802aa8a2be5fGraf Yangvoid cpu_die(void)
4240b39db28b953945232719e7ff6fb802aa8a2be5fGraf Yang{
4250b39db28b953945232719e7ff6fb802aa8a2be5fGraf Yang	complete(&cpu_killed);
4260b39db28b953945232719e7ff6fb802aa8a2be5fGraf Yang
4270b39db28b953945232719e7ff6fb802aa8a2be5fGraf Yang	atomic_dec(&init_mm.mm_users);
4280b39db28b953945232719e7ff6fb802aa8a2be5fGraf Yang	atomic_dec(&init_mm.mm_count);
4290b39db28b953945232719e7ff6fb802aa8a2be5fGraf Yang
4300b39db28b953945232719e7ff6fb802aa8a2be5fGraf Yang	local_irq_disable();
4310b39db28b953945232719e7ff6fb802aa8a2be5fGraf Yang	platform_cpu_die();
4320b39db28b953945232719e7ff6fb802aa8a2be5fGraf Yang}
4330b39db28b953945232719e7ff6fb802aa8a2be5fGraf Yang#endif
434