Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  1 /*
  2  *  linux/arch/arm/mach-realview/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/smp.h>
 16 
 17 #include <asm/cacheflush.h>
 18 #include <asm/hardware/arm_scu.h>
 19 #include <asm/hardware.h>
 20 #include <asm/io.h>
 21 #include <asm/mach-types.h>
 22 
 23 extern void realview_secondary_startup(void);
 24 
 25 /*
 26  * control for which core is the next to come out of the secondary
 27  * boot "holding pen"
 28  */
 29 volatile int __cpuinitdata pen_release = -1;
 30 
 31 static unsigned int __init get_core_count(void)
 32 {
 33         unsigned int ncores;
 34 
 35         if (machine_is_realview_eb() && core_tile_eb11mp()) {
 36                 ncores = __raw_readl(__io_address(REALVIEW_EB11MP_SCU_BASE) + SCU_CONFIG);
 37                 ncores = (ncores & 0x03) + 1;
 38         } else
 39                 ncores = 1;
 40 
 41         return ncores;
 42 }
 43 
 44 static DEFINE_SPINLOCK(boot_lock);
 45 
 46 void __cpuinit platform_secondary_init(unsigned int cpu)
 47 {
 48         /*
 49          * the primary core may have used a "cross call" soft interrupt
 50          * to get this processor out of WFI in the BootMonitor - make
 51          * sure that we are no longer being sent this soft interrupt
 52          */
 53         smp_cross_call_done(cpumask_of_cpu(cpu));
 54 
 55         /*
 56          * if any interrupts are already enabled for the primary
 57          * core (e.g. timer irq), then they will not have been enabled
 58          * for us: do so
 59          */
 60         gic_cpu_init(0, __io_address(REALVIEW_EB11MP_GIC_CPU_BASE));
 61 
 62         /*
 63          * let the primary processor know we're out of the
 64          * pen, then head off into the C entry point
 65          */
 66         pen_release = -1;
 67         smp_wmb();
 68 
 69         /*
 70          * Synchronise with the boot thread.
 71          */
 72         spin_lock(&boot_lock);
 73         spin_unlock(&boot_lock);
 74 }
 75 
 76 int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
 77 {
 78         unsigned long timeout;
 79 
 80         /*
 81          * set synchronisation state between this boot processor
 82          * and the secondary one
 83          */
 84         spin_lock(&boot_lock);
 85 
 86         /*
 87          * The secondary processor is waiting to be released from
 88          * the holding pen - release it, then wait for it to flag
 89          * that it has been released by resetting pen_release.
 90          *
 91          * Note that "pen_release" is the hardware CPU ID, whereas
 92          * "cpu" is Linux's internal ID.
 93          */
 94         pen_release = cpu;
 95         flush_cache_all();
 96 
 97         /*
 98          * XXX
 99          *
100          * This is a later addition to the booting protocol: the
101          * bootMonitor now puts secondary cores into WFI, so
102          * poke_milo() no longer gets the cores moving; we need
103          * to send a soft interrupt to wake the secondary core.
104          * Use smp_cross_call() for this, since there's little
105          * point duplicating the code here
106          */
107         smp_cross_call(cpumask_of_cpu(cpu));
108 
109         timeout = jiffies + (1 * HZ);
110         while (time_before(jiffies, timeout)) {
111                 smp_rmb();
112                 if (pen_release == -1)
113                         break;
114 
115                 udelay(10);
116         }
117 
118         /*
119          * now the secondary core is starting up let it run its
120          * calibrations, then wait for it to finish
121          */
122         spin_unlock(&boot_lock);
123 
124         return pen_release != -1 ? -ENOSYS : 0;
125 }
126 
127 static void __init poke_milo(void)
128 {
129         extern void secondary_startup(void);
130 
131         /* nobody is to be released from the pen yet */
132         pen_release = -1;
133 
134         /*
135          * write the address of secondary startup into the system-wide
136          * flags register, then clear the bottom two bits, which is what
137          * BootMonitor is waiting for
138          */
139 #if 1
140 #define REALVIEW_SYS_FLAGSS_OFFSET 0x30
141         __raw_writel(virt_to_phys(realview_secondary_startup),
142                      __io_address(REALVIEW_SYS_BASE) +
143                      REALVIEW_SYS_FLAGSS_OFFSET);
144 #define REALVIEW_SYS_FLAGSC_OFFSET 0x34
145         __raw_writel(3,
146                      __io_address(REALVIEW_SYS_BASE) +
147                      REALVIEW_SYS_FLAGSC_OFFSET);
148 #endif
149 
150         mb();
151 }
152 
153 /*
154  * Initialise the CPU possible map early - this describes the CPUs
155  * which may be present or become present in the system.
156  */
157 void __init smp_init_cpus(void)
158 {
159         unsigned int i, ncores = get_core_count();
160 
161         for (i = 0; i < ncores; i++)
162                 cpu_set(i, cpu_possible_map);
163 }
164 
165 void __init smp_prepare_cpus(unsigned int max_cpus)
166 {
167         unsigned int ncores = get_core_count();
168         unsigned int cpu = smp_processor_id();
169         int i;
170 
171         /* sanity check */
172         if (ncores == 0) {
173                 printk(KERN_ERR
174                        "Realview: strange CM count of 0? Default to 1\n");
175 
176                 ncores = 1;
177         }
178 
179         if (ncores > NR_CPUS) {
180                 printk(KERN_WARNING
181                        "Realview: no. of cores (%d) greater than configured "
182                        "maximum of %d - clipping\n",
183                        ncores, NR_CPUS);
184                 ncores = NR_CPUS;
185         }
186 
187         smp_store_cpu_info(cpu);
188 
189         /*
190          * are we trying to boot more cores than exist?
191          */
192         if (max_cpus > ncores)
193                 max_cpus = ncores;
194 
195 #ifdef CONFIG_LOCAL_TIMERS
196         /*
197          * Enable the local timer for primary CPU. If the device is
198          * dummy (!CONFIG_LOCAL_TIMERS), it was already registers in
199          * realview_timer_init
200          */
201         if (machine_is_realview_eb() && core_tile_eb11mp())
202                 local_timer_setup(cpu);
203 #endif
204 
205         /*
206          * Initialise the present map, which describes the set of CPUs
207          * actually populated at the present time.
208          */
209         for (i = 0; i < max_cpus; i++)
210                 cpu_set(i, cpu_present_map);
211 
212         /*
213          * Do we need any more CPUs? If so, then let them know where
214          * to start. Note that, on modern versions of MILO, the "poke"
215          * doesn't actually do anything until each individual core is
216          * sent a soft interrupt to get it out of WFI
217          */
218         if (max_cpus > 1)
219                 poke_milo();
220 }
221 
  This page was automatically generated by the LXR engine.