1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
|
/*
* BK Id: %F% %I% %G% %U% %#%
*/
/*
* Smp support for CHRP machines.
*
* Written by Cort Dougan (cort@cs.nmt.edu) borrowing a great
* deal of code from the sparc and intel versions.
*
* Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
*
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
#include <linux/delay.h>
#define __KERNEL_SYSCALLS__
#include <linux/unistd.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <asm/ptrace.h>
#include <asm/atomic.h>
#include <asm/irq.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/hardirq.h>
#include <asm/softirq.h>
#include <asm/sections.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/smp.h>
#include <asm/residual.h>
#include <asm/feature.h>
#include <asm/time.h>
#include "open_pic.h"
extern unsigned long smp_chrp_cpu_nr;
static int __init
smp_chrp_probe(void)
{
if (smp_chrp_cpu_nr > 1)
openpic_request_IPIs();
return smp_chrp_cpu_nr;
}
static void __init
smp_chrp_kick_cpu(int nr)
{
*(unsigned long *)KERNELBASE = nr;
asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory");
}
static void __init
smp_chrp_setup_cpu(int cpu_nr)
{
static atomic_t ready = ATOMIC_INIT(1);
static volatile int frozen = 0;
if (cpu_nr == 0) {
/* wait for all the others */
while (atomic_read(&ready) < smp_num_cpus)
barrier();
atomic_set(&ready, 1);
/* freeze the timebase */
call_rtas("freeze-time-base", 0, 1, NULL);
mb();
frozen = 1;
/* XXX assumes this is not a 601 */
set_tb(0, 0);
last_jiffy_stamp(0) = 0;
while (atomic_read(&ready) < smp_num_cpus)
barrier();
/* thaw the timebase again */
call_rtas("thaw-time-base", 0, 1, NULL);
mb();
frozen = 0;
smp_tb_synchronized = 1;
} else {
atomic_inc(&ready);
while (!frozen)
barrier();
set_tb(0, 0);
last_jiffy_stamp(0) = 0;
mb();
atomic_inc(&ready);
while (frozen)
barrier();
}
if (OpenPIC_Addr)
do_openpic_setup_cpu();
}
#ifdef CONFIG_POWER4
static void __chrp
smp_xics_message_pass(int target, int msg, unsigned long data, int wait)
{
/* for now, only do reschedule messages
since we only have one IPI */
if (msg != PPC_MSG_RESCHEDULE)
return;
for (i = 0; i < smp_num_cpus; ++i) {
if (target == MSG_ALL || target == i
|| (target == MSG_ALL_BUT_SELF
&& i != smp_processor_id()))
xics_cause_IPI(i);
}
}
static int __chrp
smp_xics_probe(void)
{
return smp_chrp_cpu_nr;
}
static void __chrp
smp_xics_setup_cpu(int cpu_nr)
{
if (cpu_nr > 0)
xics_setup_cpu();
}
#endif /* CONFIG_POWER4 */
/* CHRP with openpic */
struct smp_ops_t chrp_smp_ops __chrpdata = {
smp_openpic_message_pass,
smp_chrp_probe,
smp_chrp_kick_cpu,
smp_chrp_setup_cpu,
};
#ifdef CONFIG_POWER4
/* CHRP with new XICS interrupt controller */
struct smp_ops_t xics_smp_ops __chrpdata = {
smp_xics_message_pass,
smp_xics_probe,
smp_chrp_kick_cpu,
smp_xics_setup_cpu,
};
#endif /* CONFIG_POWER4 */
|