Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
platsmp.c
Go to the documentation of this file.
1 /*
2  * linux/arch/arm/plat-versatile/platsmp.c
3  *
4  * Copyright (C) 2002 ARM Ltd.
5  * All Rights Reserved
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  */
11 #include <linux/init.h>
12 #include <linux/errno.h>
13 #include <linux/delay.h>
14 #include <linux/device.h>
15 #include <linux/jiffies.h>
16 #include <linux/smp.h>
17 
18 #include <asm/cacheflush.h>
19 #include <asm/smp_plat.h>
20 #include <asm/hardware/gic.h>
21 
22 /*
23  * Write pen_release in a way that is guaranteed to be visible to all
24  * observers, irrespective of whether they're taking part in coherency
25  * or not. This is necessary for the hotplug code to work reliably.
26  */
27 static void __cpuinit write_pen_release(int val)
28 {
29  pen_release = val;
30  smp_wmb();
32  outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
33 }
34 
35 static DEFINE_SPINLOCK(boot_lock);
36 
38 {
39  /*
40  * if any interrupts are already enabled for the primary
41  * core (e.g. timer irq), then they will not have been enabled
42  * for us: do so
43  */
45 
46  /*
47  * let the primary processor know we're out of the
48  * pen, then head off into the C entry point
49  */
50  write_pen_release(-1);
51 
52  /*
53  * Synchronise with the boot thread.
54  */
55  spin_lock(&boot_lock);
56  spin_unlock(&boot_lock);
57 }
58 
60 {
61  unsigned long timeout;
62 
63  /*
64  * Set synchronisation state between this boot processor
65  * and the secondary one
66  */
67  spin_lock(&boot_lock);
68 
69  /*
70  * This is really belt and braces; we hold unintended secondary
71  * CPUs in the holding pen until we're ready for them. However,
72  * since we haven't sent them a soft interrupt, they shouldn't
73  * be there.
74  */
75  write_pen_release(cpu_logical_map(cpu));
76 
77  /*
78  * Send the secondary CPU a soft interrupt, thereby causing
79  * the boot monitor to read the system wide flags register,
80  * and branch to the address found there.
81  */
83 
84  timeout = jiffies + (1 * HZ);
85  while (time_before(jiffies, timeout)) {
86  smp_rmb();
87  if (pen_release == -1)
88  break;
89 
90  udelay(10);
91  }
92 
93  /*
94  * now the secondary core is starting up let it run its
95  * calibrations, then wait for it to finish
96  */
97  spin_unlock(&boot_lock);
98 
99  return pen_release != -1 ? -ENOSYS : 0;
100 }