2 This software and ancillary information (herein called SOFTWARE )
3 called LinuxBIOS is made available under the terms described
4 here. The SOFTWARE has been approved for release with associated
5 LA-CC Number 00-34 . Unless otherwise indicated, this SOFTWARE has
6 been authored by an employee or employees of the University of
7 California, operator of the Los Alamos National Laboratory under
8 Contract No. W-7405-ENG-36 with the U.S. Department of Energy. The
9 U.S. Government has rights to use, reproduce, and distribute this
10 SOFTWARE. The public may copy, distribute, prepare derivative works
11 and publicly display this SOFTWARE without charge, provided that this
12 Notice and any statement of authorship are reproduced on all copies.
13 Neither the Government nor the University makes any warranty, express
14 or implied, or assumes any liability or responsibility for the use of
15 this SOFTWARE. If SOFTWARE is modified to produce derivative works,
16 such modified SOFTWARE should be clearly marked, so as not to confuse
17 it with the version available from LANL.
19 /* Copyright 2000, Ron Minnich, Advanced Computing Lab, LANL
25 * C Bootstrap code for the LinuxBIOS
29 #include <console/console.h>
33 #include <smp/start_stop.h>
34 #include <boot/tables.h>
35 #include <part/sizeram.h>
36 #include <device/device.h>
37 #include <device/pci.h>
38 #include <device/chip.h>
40 #include <part/hard_reset.h>
41 #include <smp/atomic.h>
45 #ifndef CONFIG_MAX_PHYSICAL_CPUS
46 #define CONFIG_MAX_PHYSICAL_CPUS CONFIG_MAX_CPUS
49 #if CONFIG_FS_STREAM == 1
50 extern int filo(struct lb_memory *);
54 * Now that SMP is in linuxbios, and Linux counts on us
55 * giving accurate information about processors, we need a map
56 * of what processors are out there. This could be a bit mask,
57 * but we will be optimistic and hope we someday run on
58 * REALLY BIG SMPs. Also we may need more than one bit of
59 * info per processor at some point. I hope we don't need
60 * anything more complex than an int.
62 static unsigned long processor_map[CONFIG_MAX_CPUS];
64 static struct mem_range *get_ramsize(void)
66 struct mem_range *mem = 0;
71 printk_emerg("No memory size information!\n");
73 /* Ensure this loop is not optimized away */
74 asm volatile("":/* outputs */:/*inputs */ :"memory");
82 /* Number of cpus that are currently running in linuxbios */
83 static atomic_t active_cpus = ATOMIC_INIT(1);
86 * @brief Initialize secondary processors.
89 * @todo move this into a method of per cpu data structure.
91 void secondary_cpu_init(void)
93 struct mem_range *mem;
97 atomic_inc(&active_cpus);
99 printk_debug("%s\n", __FUNCTION__);
101 id = cpu_initialize(mem);
102 index = processor_index(id);
103 printk_debug("%s %d/%u\n", __FUNCTION__ , index, id);
104 processor_map[index] = CPU_ENABLED;
106 atomic_dec(&active_cpus);
110 static void wait_for_other_cpus(void)
112 int old_active_count, active_count;
114 old_active_count = 1;
116 active_count = atomic_read(&active_cpus);
117 while (active_count > 1) {
118 if (active_count != old_active_count) {
119 printk_info("Waiting for %d CPUS to stop\n",
121 old_active_count = active_count;
123 active_count = atomic_read(&active_cpus);
126 for (i = 0; i < CONFIG_MAX_CPUS; i++) {
127 if (!(processor_map[i] & CPU_ENABLED)) {
128 printk_err("CPU %d did not initialize!\n", i);
129 processor_map[i] = 0;
133 printk_debug("All AP CPUs stopped\n");
136 #else /* CONIFG_SMP */
137 #define wait_for_other_cpus() do {} while(0)
138 #endif /* CONFIG_SMP */
141 * @brief Main program of LinuxBIOS
143 * @param boot_complete
145 void hardwaremain(int boot_complete)
147 /* Processor ID of the BOOT cpu (i.e. the one running this code) */
148 unsigned long boot_cpu;
150 struct mem_range *mem, *tmem;
151 struct lb_memory *lb_mem;
152 unsigned long totalmem;
156 CONFIGURE(CONF_PASS_PRE_CONSOLE);
158 /* displayinit MUST PRECEDE ALL PRINTK! */
162 printk_notice("LinuxBIOS-%s%s %s %s...\n",
163 linuxbios_version, linuxbios_extra_version,
164 linuxbios_build, (boot_complete)?"rebooting":"booting");
168 /* If we have already booted attempt a hard reboot */
173 CONFIGURE(CONF_PASS_PRE_PCI);
175 /* determine how software can generate PCI configuration transactions
177 printk_info("Finding PCI configuration type.\n");
181 /* convert static device structures into dynamic device structures
182 * before probing dynamic devices. */
183 enumerate_static_devices();
185 /* probe the existence of dynamic devices and construct the dynamic
190 /* probe and assign the resources required by the dynamic devices */
194 /* enable the resources probed and assigned in dev_configure() */
197 /* do the device specific init in additional to simple resources
198 * allocation performed in dev_enable() */
202 CONFIGURE(CONF_PASS_POST_PCI);
204 /* this is done last because some devices may 'steal' memory from
205 * the system during device initialization. */
208 for (totalmem = 0, tmem = mem; tmem->sizek; tmem++) {
209 totalmem += tmem->sizek;
211 /* Round to the nearest mega */
212 printk_info("totalram: %ldM\n", (totalmem + 512) >> 10);
214 /* fully initialize the boot processor */
215 boot_cpu = cpu_initialize(mem);
216 boot_index = processor_index(boot_cpu);
217 printk_spew("BOOT CPU is %d\n", boot_cpu);
218 processor_map[boot_index] = CPU_BOOTPROCESSOR|CPU_ENABLED;
220 /* start up other processors, it works like a pthread_create() or
221 * fork(), instead of running the initialization code for all devices
222 * as the boot processor, they start from secondary_cpu_init(), doing
223 * cpu initialization only. */
225 startup_other_cpus(processor_map);
227 /* like pthread_join() or wait(), wait other processors finishing
228 * their execution of secondary_cpu_init() and make certain we are
229 * the only cpu running in LinuxBIOS */
230 wait_for_other_cpus();
232 /* Now that we have collected all of our information, write our
233 * configuration tables. */
234 lb_mem = write_tables(mem, processor_map);
236 CONFIGURE(CONF_PASS_PRE_BOOT);
238 #if CONFIG_FS_STREAM == 1