PageRenderTime 22ms CodeModel.GetById 1ms app.highlight 18ms RepoModel.GetById 1ms app.codeStats 0ms

/arch/mips/kernel/smp.c

https://bitbucket.org/evzijst/gittest
C | 425 lines | 253 code | 70 blank | 102 comment | 41 complexity | 2c2e8fef45b8fa4be4090ac3b2f85f66 MD5 | raw file
  1/*
  2 * This program is free software; you can redistribute it and/or
  3 * modify it under the terms of the GNU General Public License
  4 * as published by the Free Software Foundation; either version 2
  5 * of the License, or (at your option) any later version.
  6 *
  7 * This program is distributed in the hope that it will be useful,
  8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 10 * GNU General Public License for more details.
 11 *
 12 * You should have received a copy of the GNU General Public License
 13 * along with this program; if not, write to the Free Software
 14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 15 *
 16 * Copyright (C) 2000, 2001 Kanoj Sarcar
 17 * Copyright (C) 2000, 2001 Ralf Baechle
 18 * Copyright (C) 2000, 2001 Silicon Graphics, Inc.
 19 * Copyright (C) 2000, 2001, 2003 Broadcom Corporation
 20 */
 21#include <linux/cache.h>
 22#include <linux/delay.h>
 23#include <linux/init.h>
 24#include <linux/interrupt.h>
 25#include <linux/spinlock.h>
 26#include <linux/threads.h>
 27#include <linux/module.h>
 28#include <linux/time.h>
 29#include <linux/timex.h>
 30#include <linux/sched.h>
 31#include <linux/cpumask.h>
 32
 33#include <asm/atomic.h>
 34#include <asm/cpu.h>
 35#include <asm/processor.h>
 36#include <asm/system.h>
 37#include <asm/mmu_context.h>
 38#include <asm/smp.h>
 39
 40cpumask_t phys_cpu_present_map;		/* Bitmask of available CPUs */
 41volatile cpumask_t cpu_callin_map;	/* Bitmask of started secondaries */
 42cpumask_t cpu_online_map;		/* Bitmask of currently online CPUs */
 43int __cpu_number_map[NR_CPUS];		/* Map physical to logical */
 44int __cpu_logical_map[NR_CPUS];		/* Map logical to physical */
 45
 46EXPORT_SYMBOL(phys_cpu_present_map);
 47EXPORT_SYMBOL(cpu_online_map);
 48
 49static void smp_tune_scheduling (void)
 50{
 51	struct cache_desc *cd = &current_cpu_data.scache;
 52	unsigned long cachesize;       /* kB   */
 53	unsigned long bandwidth = 350; /* MB/s */
 54	unsigned long cpu_khz;
 55
 56	/*
 57	 * Crude estimate until we actually meassure ...
 58	 */
 59	cpu_khz = loops_per_jiffy * 2 * HZ / 1000;
 60
 61	/*
 62	 * Rough estimation for SMP scheduling, this is the number of
 63	 * cycles it takes for a fully memory-limited process to flush
 64	 * the SMP-local cache.
 65	 *
 66	 * (For a P5 this pretty much means we will choose another idle
 67	 *  CPU almost always at wakeup time (this is due to the small
 68	 *  L1 cache), on PIIs it's around 50-100 usecs, depending on
 69	 *  the cache size)
 70	 */
 71	if (!cpu_khz)
 72		return;
 73
 74	cachesize = cd->linesz * cd->sets * cd->ways;
 75}
 76
 77extern void __init calibrate_delay(void);
 78extern ATTRIB_NORET void cpu_idle(void);
 79
 80/*
 81 * First C code run on the secondary CPUs after being started up by
 82 * the master.
 83 */
 84asmlinkage void start_secondary(void)
 85{
 86	unsigned int cpu = smp_processor_id();
 87
 88	cpu_probe();
 89	cpu_report();
 90	per_cpu_trap_init();
 91	prom_init_secondary();
 92
 93	/*
 94	 * XXX parity protection should be folded in here when it's converted
 95	 * to an option instead of something based on .cputype
 96	 */
 97
 98	calibrate_delay();
 99	cpu_data[cpu].udelay_val = loops_per_jiffy;
100
101	prom_smp_finish();
102
103	cpu_set(cpu, cpu_callin_map);
104
105	cpu_idle();
106}
107
108DEFINE_SPINLOCK(smp_call_lock);
109
110struct call_data_struct *call_data;
111
112/*
113 * Run a function on all other CPUs.
114 *  <func>      The function to run. This must be fast and non-blocking.
115 *  <info>      An arbitrary pointer to pass to the function.
116 *  <retry>     If true, keep retrying until ready.
117 *  <wait>      If true, wait until function has completed on other CPUs.
118 *  [RETURNS]   0 on success, else a negative status code.
119 *
120 * Does not return until remote CPUs are nearly ready to execute <func>
121 * or are or have executed.
122 *
123 * You must not call this function with disabled interrupts or from a
124 * hardware interrupt handler or from a bottom half handler.
125 */
126int smp_call_function (void (*func) (void *info), void *info, int retry,
127								int wait)
128{
129	struct call_data_struct data;
130	int i, cpus = num_online_cpus() - 1;
131	int cpu = smp_processor_id();
132
133	if (!cpus)
134		return 0;
135
136	/* Can deadlock when called with interrupts disabled */
137	WARN_ON(irqs_disabled());
138
139	data.func = func;
140	data.info = info;
141	atomic_set(&data.started, 0);
142	data.wait = wait;
143	if (wait)
144		atomic_set(&data.finished, 0);
145
146	spin_lock(&smp_call_lock);
147	call_data = &data;
148	mb();
149
150	/* Send a message to all other CPUs and wait for them to respond */
151	for (i = 0; i < NR_CPUS; i++)
152		if (cpu_online(i) && i != cpu)
153			core_send_ipi(i, SMP_CALL_FUNCTION);
154
155	/* Wait for response */
156	/* FIXME: lock-up detection, backtrace on lock-up */
157	while (atomic_read(&data.started) != cpus)
158		barrier();
159
160	if (wait)
161		while (atomic_read(&data.finished) != cpus)
162			barrier();
163	spin_unlock(&smp_call_lock);
164
165	return 0;
166}
167
168void smp_call_function_interrupt(void)
169{
170	void (*func) (void *info) = call_data->func;
171	void *info = call_data->info;
172	int wait = call_data->wait;
173
174	/*
175	 * Notify initiating CPU that I've grabbed the data and am
176	 * about to execute the function.
177	 */
178	mb();
179	atomic_inc(&call_data->started);
180
181	/*
182	 * At this point the info structure may be out of scope unless wait==1.
183	 */
184	irq_enter();
185	(*func)(info);
186	irq_exit();
187
188	if (wait) {
189		mb();
190		atomic_inc(&call_data->finished);
191	}
192}
193
194static void stop_this_cpu(void *dummy)
195{
196	/*
197	 * Remove this CPU:
198	 */
199	cpu_clear(smp_processor_id(), cpu_online_map);
200	local_irq_enable();	/* May need to service _machine_restart IPI */
201	for (;;);		/* Wait if available. */
202}
203
204void smp_send_stop(void)
205{
206	smp_call_function(stop_this_cpu, NULL, 1, 0);
207}
208
209void __init smp_cpus_done(unsigned int max_cpus)
210{
211	prom_cpus_done();
212}
213
214/* called from main before smp_init() */
215void __init smp_prepare_cpus(unsigned int max_cpus)
216{
217	cpu_data[0].udelay_val = loops_per_jiffy;
218	init_new_context(current, &init_mm);
219	current_thread_info()->cpu = 0;
220	smp_tune_scheduling();
221	prom_prepare_cpus(max_cpus);
222}
223
224/* preload SMP state for boot cpu */
225void __devinit smp_prepare_boot_cpu(void)
226{
227	/*
228	 * This assumes that bootup is always handled by the processor
229	 * with the logic and physical number 0.
230	 */
231	__cpu_number_map[0] = 0;
232	__cpu_logical_map[0] = 0;
233	cpu_set(0, phys_cpu_present_map);
234	cpu_set(0, cpu_online_map);
235	cpu_set(0, cpu_callin_map);
236}
237
238/*
239 * Startup the CPU with this logical number
240 */
241static int __init do_boot_cpu(int cpu)
242{
243	struct task_struct *idle;
244
245	/*
246	 * The following code is purely to make sure
247	 * Linux can schedule processes on this slave.
248	 */
249	idle = fork_idle(cpu);
250	if (IS_ERR(idle))
251		panic("failed fork for CPU %d\n", cpu);
252
253	prom_boot_secondary(cpu, idle);
254
255	/* XXXKW timeout */
256	while (!cpu_isset(cpu, cpu_callin_map))
257		udelay(100);
258
259	cpu_set(cpu, cpu_online_map);
260
261	return 0;
262}
263
264/*
265 * Called once for each "cpu_possible(cpu)".  Needs to spin up the cpu
266 * and keep control until "cpu_online(cpu)" is set.  Note: cpu is
267 * physical, not logical.
268 */
269int __devinit __cpu_up(unsigned int cpu)
270{
271	int ret;
272
273	/* Processor goes to start_secondary(), sets online flag */
274	ret = do_boot_cpu(cpu);
275	if (ret < 0)
276		return ret;
277
278	return 0;
279}
280
281/* Not really SMP stuff ... */
282int setup_profiling_timer(unsigned int multiplier)
283{
284	return 0;
285}
286
287static void flush_tlb_all_ipi(void *info)
288{
289	local_flush_tlb_all();
290}
291
292void flush_tlb_all(void)
293{
294	on_each_cpu(flush_tlb_all_ipi, 0, 1, 1);
295}
296
297static void flush_tlb_mm_ipi(void *mm)
298{
299	local_flush_tlb_mm((struct mm_struct *)mm);
300}
301
302/*
303 * The following tlb flush calls are invoked when old translations are
304 * being torn down, or pte attributes are changing. For single threaded
305 * address spaces, a new context is obtained on the current cpu, and tlb
306 * context on other cpus are invalidated to force a new context allocation
307 * at switch_mm time, should the mm ever be used on other cpus. For
308 * multithreaded address spaces, intercpu interrupts have to be sent.
309 * Another case where intercpu interrupts are required is when the target
310 * mm might be active on another cpu (eg debuggers doing the flushes on
311 * behalf of debugees, kswapd stealing pages from another process etc).
312 * Kanoj 07/00.
313 */
314
315void flush_tlb_mm(struct mm_struct *mm)
316{
317	preempt_disable();
318
319	if ((atomic_read(&mm->mm_users) != 1) || (current->mm != mm)) {
320		smp_call_function(flush_tlb_mm_ipi, (void *)mm, 1, 1);
321	} else {
322		int i;
323		for (i = 0; i < num_online_cpus(); i++)
324			if (smp_processor_id() != i)
325				cpu_context(i, mm) = 0;
326	}
327	local_flush_tlb_mm(mm);
328
329	preempt_enable();
330}
331
332struct flush_tlb_data {
333	struct vm_area_struct *vma;
334	unsigned long addr1;
335	unsigned long addr2;
336};
337
338static void flush_tlb_range_ipi(void *info)
339{
340	struct flush_tlb_data *fd = (struct flush_tlb_data *)info;
341
342	local_flush_tlb_range(fd->vma, fd->addr1, fd->addr2);
343}
344
345void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
346{
347	struct mm_struct *mm = vma->vm_mm;
348
349	preempt_disable();
350	if ((atomic_read(&mm->mm_users) != 1) || (current->mm != mm)) {
351		struct flush_tlb_data fd;
352
353		fd.vma = vma;
354		fd.addr1 = start;
355		fd.addr2 = end;
356		smp_call_function(flush_tlb_range_ipi, (void *)&fd, 1, 1);
357	} else {
358		int i;
359		for (i = 0; i < num_online_cpus(); i++)
360			if (smp_processor_id() != i)
361				cpu_context(i, mm) = 0;
362	}
363	local_flush_tlb_range(vma, start, end);
364	preempt_enable();
365}
366
367static void flush_tlb_kernel_range_ipi(void *info)
368{
369	struct flush_tlb_data *fd = (struct flush_tlb_data *)info;
370
371	local_flush_tlb_kernel_range(fd->addr1, fd->addr2);
372}
373
374void flush_tlb_kernel_range(unsigned long start, unsigned long end)
375{
376	struct flush_tlb_data fd;
377
378	fd.addr1 = start;
379	fd.addr2 = end;
380	on_each_cpu(flush_tlb_kernel_range_ipi, (void *)&fd, 1, 1);
381}
382
383static void flush_tlb_page_ipi(void *info)
384{
385	struct flush_tlb_data *fd = (struct flush_tlb_data *)info;
386
387	local_flush_tlb_page(fd->vma, fd->addr1);
388}
389
390void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
391{
392	preempt_disable();
393	if ((atomic_read(&vma->vm_mm->mm_users) != 1) || (current->mm != vma->vm_mm)) {
394		struct flush_tlb_data fd;
395
396		fd.vma = vma;
397		fd.addr1 = page;
398		smp_call_function(flush_tlb_page_ipi, (void *)&fd, 1, 1);
399	} else {
400		int i;
401		for (i = 0; i < num_online_cpus(); i++)
402			if (smp_processor_id() != i)
403				cpu_context(i, vma->vm_mm) = 0;
404	}
405	local_flush_tlb_page(vma, page);
406	preempt_enable();
407}
408
409static void flush_tlb_one_ipi(void *info)
410{
411	unsigned long vaddr = (unsigned long) info;
412
413	local_flush_tlb_one(vaddr);
414}
415
416void flush_tlb_one(unsigned long vaddr)
417{
418	smp_call_function(flush_tlb_one_ipi, (void *) vaddr, 1, 1);
419	local_flush_tlb_one(vaddr);
420}
421
422EXPORT_SYMBOL(flush_tlb_page);
423EXPORT_SYMBOL(flush_tlb_one);
424EXPORT_SYMBOL(cpu_data);
425EXPORT_SYMBOL(synchronize_irq);