File: /usr/src/linux/arch/sparc/kernel/smp.c

1     /* smp.c: Sparc SMP support.
2      *
3      * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
4      * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
5      */
6     
7     #include <asm/head.h>
8     
9     #include <linux/kernel.h>
10     #include <linux/sched.h>
11     #include <linux/threads.h>
12     #include <linux/smp.h>
13     #include <linux/smp_lock.h>
14     #include <linux/interrupt.h>
15     #include <linux/kernel_stat.h>
16     #include <linux/init.h>
17     #include <linux/spinlock.h>
18     #include <linux/mm.h>
19     
20     #include <asm/ptrace.h>
21     #include <asm/atomic.h>
22     
23     #include <asm/delay.h>
24     #include <asm/irq.h>
25     #include <asm/page.h>
26     #include <asm/pgalloc.h>
27     #include <asm/pgtable.h>
28     #include <asm/oplib.h>
29     #include <asm/hardirq.h>
30     #include <asm/softirq.h>
31     
32     #define __KERNEL_SYSCALLS__
33     #include <linux/unistd.h>
34     
35     #define IRQ_RESCHEDULE		13
36     #define IRQ_STOP_CPU		14
37     #define IRQ_CROSS_CALL		15
38     
39     volatile int smp_processors_ready = 0;
40     unsigned long cpu_present_map = 0;
41     int smp_num_cpus = 1;
42     int smp_threads_ready=0;
43     unsigned char mid_xlate[NR_CPUS] = { 0, 0, 0, 0, };
44     volatile unsigned long cpu_callin_map[NR_CPUS] __initdata = {0,};
45     #ifdef NOTUSED
46     volatile unsigned long smp_spinning[NR_CPUS] = { 0, };
47     #endif
48     unsigned long smp_proc_in_lock[NR_CPUS] = { 0, };
49     struct cpuinfo_sparc cpu_data[NR_CPUS];
50     unsigned long cpu_offset[NR_CPUS];
51     unsigned char boot_cpu_id = 0;
52     unsigned char boot_cpu_id4 = 0; /* boot_cpu_id << 2 */
53     int smp_activated = 0;
54     volatile int __cpu_number_map[NR_CPUS];
55     volatile int __cpu_logical_map[NR_CPUS];
56     cycles_t cacheflush_time = 0; /* XXX */
57     
58     /* The only guaranteed locking primitive available on all Sparc
59      * processors is 'ldstub [%reg + immediate], %dest_reg' which atomically
60      * places the current byte at the effective address into dest_reg and
61      * places 0xff there afterwards.  Pretty lame locking primitive
62      * compared to the Alpha and the Intel no?  Most Sparcs have 'swap'
63      * instruction which is much better...
64      */
65     
66     /* Kernel spinlock */
67     spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
68     
69     /* Used to make bitops atomic */
70     unsigned char bitops_spinlock = 0;
71     
72     volatile unsigned long ipi_count;
73     
74     volatile int smp_process_available=0;
75     volatile int smp_commenced = 0;
76     
77     /* Not supported on Sparc yet. */
78     void __init smp_setup(char *str, int *ints)
79     {
80     }
81     
82     /*
83      *	The bootstrap kernel entry code has set these up. Save them for
84      *	a given CPU
85      */
86     
87     void __init smp_store_cpu_info(int id)
88     {
89     	cpu_data[id].udelay_val = loops_per_jiffy; /* this is it on sparc. */
90     }
91     
92     void __init smp_commence(void)
93     {
94     	/*
95     	 *	Lets the callin's below out of their loop.
96     	 */
97     	local_flush_cache_all();
98     	local_flush_tlb_all();
99     	smp_commenced = 1;
100     	local_flush_cache_all();
101     	local_flush_tlb_all();
102     }
103     
104     /* Only broken Intel needs this, thus it should not even be referenced
105      * globally...
106      */
107     void __init initialize_secondary(void)
108     {
109     }
110     
111     extern int cpu_idle(void);
112     
113     /* Activate a secondary processor. */
114     int start_secondary(void *unused)
115     {
116     	prom_printf("Start secondary called. Should not happen\n");
117     	return cpu_idle();
118     }
119     
120     void cpu_panic(void)
121     {
122     	printk("CPU[%d]: Returns from cpu_idle!\n", smp_processor_id());
123     	panic("SMP bolixed\n");
124     }
125     
126     /*
127      *	Cycle through the processors asking the PROM to start each one.
128      */
129      
130     extern struct prom_cpuinfo linux_cpus[NR_CPUS];
131     struct linux_prom_registers smp_penguin_ctable __initdata = { 0 };
132     
133     void __init smp_boot_cpus(void)
134     {
135     	extern void smp4m_boot_cpus(void);
136     	extern void smp4d_boot_cpus(void);
137     	
138     	if (sparc_cpu_model == sun4m)
139     		smp4m_boot_cpus();
140     	else
141     		smp4d_boot_cpus();
142     }
143     
144     void smp_flush_cache_all(void)
145     {
146     	xc0((smpfunc_t) BTFIXUP_CALL(local_flush_cache_all));
147     	local_flush_cache_all();
148     }
149     
150     void smp_flush_tlb_all(void)
151     {
152     	xc0((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_all));
153     	local_flush_tlb_all();
154     }
155     
156     void smp_flush_cache_mm(struct mm_struct *mm)
157     {
158     	if(mm->context != NO_CONTEXT) {
159     		if(mm->cpu_vm_mask != (1 << smp_processor_id()))
160     			xc1((smpfunc_t) BTFIXUP_CALL(local_flush_cache_mm), (unsigned long) mm);
161     		local_flush_cache_mm(mm);
162     	}
163     }
164     
165     void smp_flush_tlb_mm(struct mm_struct *mm)
166     {
167     	if(mm->context != NO_CONTEXT) {
168     		if(mm->cpu_vm_mask != (1 << smp_processor_id())) {
169     			xc1((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_mm), (unsigned long) mm);
170     			if(atomic_read(&mm->mm_users) == 1 && current->active_mm == mm)
171     				mm->cpu_vm_mask = (1 << smp_processor_id());
172     		}
173     		local_flush_tlb_mm(mm);
174     	}
175     }
176     
177     void smp_flush_cache_range(struct mm_struct *mm, unsigned long start,
178     			   unsigned long end)
179     {
180     	if(mm->context != NO_CONTEXT) {
181     		if(mm->cpu_vm_mask != (1 << smp_processor_id()))
182     			xc3((smpfunc_t) BTFIXUP_CALL(local_flush_cache_range), (unsigned long) mm, start, end);
183     		local_flush_cache_range(mm, start, end);
184     	}
185     }
186     
187     void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start,
188     			 unsigned long end)
189     {
190     	if(mm->context != NO_CONTEXT) {
191     		if(mm->cpu_vm_mask != (1 << smp_processor_id()))
192     			xc3((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_range), (unsigned long) mm, start, end);
193     		local_flush_tlb_range(mm, start, end);
194     	}
195     }
196     
197     void smp_flush_cache_page(struct vm_area_struct *vma, unsigned long page)
198     {
199     	struct mm_struct *mm = vma->vm_mm;
200     
201     	if(mm->context != NO_CONTEXT) {
202     		if(mm->cpu_vm_mask != (1 << smp_processor_id()))
203     			xc2((smpfunc_t) BTFIXUP_CALL(local_flush_cache_page), (unsigned long) vma, page);
204     		local_flush_cache_page(vma, page);
205     	}
206     }
207     
208     void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
209     {
210     	struct mm_struct *mm = vma->vm_mm;
211     
212     	if(mm->context != NO_CONTEXT) {
213     		if(mm->cpu_vm_mask != (1 << smp_processor_id()))
214     			xc2((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_page), (unsigned long) vma, page);
215     		local_flush_tlb_page(vma, page);
216     	}
217     }
218     
219     void smp_flush_page_to_ram(unsigned long page)
220     {
221     	/* Current theory is that those who call this are the one's
222     	 * who have just dirtied their cache with the pages contents
223     	 * in kernel space, therefore we only run this on local cpu.
224     	 *
225     	 * XXX This experiment failed, research further... -DaveM
226     	 */
227     #if 1
228     	xc1((smpfunc_t) BTFIXUP_CALL(local_flush_page_to_ram), page);
229     #endif
230     	local_flush_page_to_ram(page);
231     }
232     
233     void smp_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr)
234     {
235     	if(mm->cpu_vm_mask != (1 << smp_processor_id()))
236     		xc2((smpfunc_t) BTFIXUP_CALL(local_flush_sig_insns), (unsigned long) mm, insn_addr);
237     	local_flush_sig_insns(mm, insn_addr);
238     }
239     
240     /* Reschedule call back. */
241     void smp_reschedule_irq(void)
242     {
243     	current->need_resched = 1;
244     }
245     
246     /* Stopping processors. */
247     void smp_stop_cpu_irq(void)
248     {
249     	__sti();
250     	while(1)
251     		barrier();
252     }
253     
254     unsigned int prof_multiplier[NR_CPUS];
255     unsigned int prof_counter[NR_CPUS];
256     extern unsigned int lvl14_resolution;
257     
258     int setup_profiling_timer(unsigned int multiplier)
259     {
260     	int i;
261     	unsigned long flags;
262     
263     	/* Prevent level14 ticker IRQ flooding. */
264     	if((!multiplier) || (lvl14_resolution / multiplier) < 500)
265     		return -EINVAL;
266     
267     	save_and_cli(flags);
268     	for(i = 0; i < NR_CPUS; i++) {
269     		if(cpu_present_map & (1 << i)) {
270     			load_profile_irq(mid_xlate[i], lvl14_resolution / multiplier);
271     			prof_multiplier[i] = multiplier;
272     		}
273     	}
274     	restore_flags(flags);
275     
276     	return 0;
277     }
278     
279     int smp_bogo_info(char *buf)
280     {
281     	int len = 0, i;
282     	
283     	for (i = 0; i < NR_CPUS; i++)
284     		if (cpu_present_map & (1 << i))
285     			len += sprintf(buf + len, "Cpu%dBogo\t: %lu.%02lu\n", 
286     					i,
287     					cpu_data[i].udelay_val/(500000/HZ),
288     					(cpu_data[i].udelay_val/(5000/HZ))%100);
289     	return len;
290     }
291     
292     int smp_info(char *buf)
293     {
294     	int len = 0, i;
295     	
296     	for (i = 0; i < NR_CPUS; i++)
297     		if (cpu_present_map & (1 << i))
298     			len += sprintf(buf + len, "CPU%d\t\t: online\n", i);
299     	return len;
300     }
301