cleanup
[linux-2.4.21-pre4.git] / arch / ppc / platforms / iSeries_smp.c
1 /*
2  * BK Id: SCCS/s.iSeries_smp.c 1.6 11/08/01 22:41:15 paulus
3  */
4 /*
5  * SMP support for iSeries/LPAR.
6  *
7  * Copyright (C) 2001 IBM Corp.
8  *
9  *  This program is free software; you can redistribute it and/or
10  *  modify it under the terms of the GNU General Public License
11  *  as published by the Free Software Foundation; either version
12  *  2 of the License, or (at your option) any later version.
13  */
14
15 #include <linux/config.h>
16 #include <linux/kernel.h>
17 #include <linux/sched.h>
18 #include <linux/smp.h>
19 #include <linux/smp_lock.h>
20 #include <linux/interrupt.h>
21 #include <linux/kernel_stat.h>
22 #include <linux/delay.h>
23 #define __KERNEL_SYSCALLS__
24 #include <linux/unistd.h>
25 #include <linux/init.h>
26 #include <linux/spinlock.h>
27
28 #include <asm/ptrace.h>
29 #include <asm/atomic.h>
30 #include <asm/irq.h>
31 #include <asm/page.h>
32 #include <asm/pgtable.h>
33 #include <asm/hardirq.h>
34 #include <asm/softirq.h>
35 #include <asm/io.h>
36 #include <asm/prom.h>
37 #include <asm/smp.h>
38 #include <asm/residual.h>
39 #include <asm/time.h>
40
41 #include <asm/iSeries/LparData.h>
42 #include <asm/iSeries/HvCall.h>
43 extern u64 get_tb64(void);
44 extern u64 next_jiffy_update_tb[];
45
46 static unsigned long iSeries_smp_message[NR_CPUS];
47
48 void iSeries_smp_message_recv( struct pt_regs * regs )
49 {
50         int cpu = smp_processor_id();
51         int msg;
52
53         if ( smp_num_cpus < 2 )
54                 return;
55
56         for ( msg = 0; msg < 4; ++msg )
57                 if ( test_and_clear_bit( msg, &iSeries_smp_message[cpu] ) )
58                         smp_message_recv( msg, regs );
59
60 }
61
62 static void smp_iSeries_message_pass(int target, int msg, unsigned long data, int wait)
63 {
64         int i;
65         for (i = 0; i < smp_num_cpus; ++i) {
66                 if ( (target == MSG_ALL) ||
67                         (target == i) ||
68                         ((target == MSG_ALL_BUT_SELF) && (i != smp_processor_id())) ) {
69                         set_bit( msg, &iSeries_smp_message[i] );
70                         HvCall_sendIPI(&(xPaca[i]));
71                 }
72         }
73 }
74
75 static int smp_iSeries_probe(void)
76 {
77         unsigned i;
78         unsigned np;
79         struct ItLpPaca * lpPaca;
80
81         np = 0;
82         for (i=0; i<maxPacas; ++i) {
83                 lpPaca = xPaca[i].xLpPacaPtr;
84                 if ( lpPaca->xDynProcStatus < 2 )
85                         ++np;
86         }
87
88         smp_tb_synchronized = 1;
89         return np;
90 }
91
92 extern unsigned long decr_overclock;
93 static void smp_iSeries_kick_cpu(int nr)
94 {
95         struct ItLpPaca * lpPaca;
96         // Verify we have a Paca for processor nr
97         if ( ( nr <= 0 ) ||
98                 ( nr >= maxPacas ) )
99                 return;
100         // Verify that our partition has a processor nr
101         lpPaca = xPaca[nr].xLpPacaPtr;
102         if ( lpPaca->xDynProcStatus >= 2 )
103                 return;
104         xPaca[nr].default_decr = tb_ticks_per_jiffy / decr_overclock;
105         // The processor is currently spinning, waiting
106         // for the xProcStart field to become non-zero
107         // After we set xProcStart, the processor will
108         // continue on to secondary_start in iSeries_head.S
109         xPaca[nr].xProcStart = 1;
110 }
111
112 static void smp_iSeries_setup_cpu(int nr)
113 {
114         set_dec( xPaca[nr].default_decr );
115 }
116
117 void smp_iSeries_space_timers( unsigned nr )
118 {
119         unsigned offset,i;
120         
121         offset = tb_ticks_per_jiffy / nr;
122         for ( i=1; i<nr; ++i ) {
123                 next_jiffy_update_tb[i] = next_jiffy_update_tb[i-1] + offset;
124         }
125 }
126
127 struct smp_ops_t iSeries_smp_ops = {
128    smp_iSeries_message_pass,
129    smp_iSeries_probe,
130    smp_iSeries_kick_cpu,
131    smp_iSeries_setup_cpu
132 };
133