/* SMP support routines.
*
* Copyright (C) 2006-2008 Panasonic Corporation
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/init.h>
#include <linux/jiffies.h>
#include <linux/cpumask.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/profile.h>
#include <linux/smp.h>
#include <linux/cpu.h>
#include <asm/tlbflush.h>
#include <asm/bitops.h>
#include <asm/processor.h>
#include <asm/bug.h>
#include <asm/exceptions.h>
#include <asm/hardirq.h>
#include <asm/fpu.h>
#include <asm/mmu_context.h>
#include <asm/thread_info.h>
#include <asm/cpu-regs.h>
#include <asm/intctl-regs.h>
#include "internal.h"
#ifdef CONFIG_HOTPLUG_CPU
#include <asm/cacheflush.h>
static unsigned long sleep_mode[NR_CPUS];
static void run_sleep_cpu(unsigned int cpu);
static void run_wakeup_cpu(unsigned int cpu);
#endif /* CONFIG_HOTPLUG_CPU */
/*
* Debug Message function
*/
#undef DEBUG_SMP
#ifdef DEBUG_SMP
#define Dprintk(fmt, ...) printk(KERN_DEBUG fmt, ##__VA_ARGS__)
#else
#define Dprintk(fmt, ...) no_printk(KERN_DEBUG fmt, ##__VA_ARGS__)
#endif
/* timeout value in msec for smp_nmi_call_function. zero is no timeout. */
#define CALL_FUNCTION_NMI_IPI_TIMEOUT 0
/*
* Structure and data for smp_nmi_call_function().
*/
struct nmi_call_data_struct {
smp_call_func_t func;
void *info;
cpumask_t started;
cpumask_t finished;
int wait;
char size_alignment[0]
__attribute__ ((__aligned__(SMP_CACHE_BYTES)));
} __attribute__ ((__aligned__(SMP_CACHE_BYTES)));
static DEFINE_SPINLOCK(smp_nmi_call_lock);
static struct nmi_call_data_struct *nmi_call_data;
/*
* Data structures and variables
*/
static cpumask_t cpu_callin_map; /* Bitmask of callin CPUs */
static cpumask_t cpu_callout_map; /* Bitmask of callout CPUs */
cpumask_t cpu_boot_map; /* Bitmask of boot APs */
unsigned long start_stack[NR_CPUS - 1];
/*
* Per CPU parameters
*/
struct mn10300_cpuinfo cpu_data[NR_CPUS] __cacheline_aligned;
static int cpucount; /* The count of boot CPUs */
static cpumask_t smp_commenced_mask;
cpumask_t cpu_initialized __initdata = CPU_MASK_NONE;
/*
* Function Prototypes
*/
static int do_boot_cpu(int);
static void smp_show_cpu_info(int cpu_id);
static void smp_callin(void);
static void smp_online(void);
static void smp_store_cpu_info(int);
static void smp_cpu_init(void);
static void smp_tune_scheduling(void);
static void send_IPI_mask(const cpumask_t *cpumask, int irq);
static void init_ipi(void);
/*
* IPI Initialization interrupt definitions
*/
static void mn10300_ipi_disable(unsigned int irq);
static void mn10300_ipi_enable(unsigned int irq);
static void mn10300_ipi_chip_disable(struct irq_data *d);
static void mn10300_ipi_chip_enable(struct irq_data *d);
static void mn10300_ipi_ack(struct irq_data *d);
static void mn10300_ipi_nop(struct irq_data *d);
static struct irq_chip mn10300_ipi_type = {
.name = "cpu_ipi",
.irq_disable = mn10300_ipi_chip_disable,
.irq_enable = mn10300_ipi_chip_enable,
.irq_ack = mn10300_ipi_ack,
.irq_eoi = mn10300_ipi_nop
};
static irqreturn_t smp_reschedule_interrupt(int irq, void *dev_id);
static irqreturn_t smp_call_function_interrupt(int irq, void *dev_id);
static struct irqaction