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
50 * Now that SMP is in linuxbios, and Linux counts on us
51 * giving accurate information about processors, we need a map
52 * of what processors are out there. This could be a bit mask,
53 * but we will be optimistic and hope we someday run on
54 * REALLY BIG SMPs. Also we may need more than one bit of
55 * info per processor at some point. I hope we don't need
56 * anything more complex than an int.
58 static unsigned long processor_map[CONFIG_MAX_CPUS];
60 static struct mem_range *get_ramsize(void)
62 struct mem_range *mem = 0;
67 printk_emerg("No memory size information!\n");
69 /* Ensure this loop is not optimized away */
70 asm volatile("":/* outputs */:/*inputs */ :"memory");
78 /* Number of cpus that are currently running in linuxbios */
79 static atomic_t active_cpus = ATOMIC_INIT(1);
82 * @brief Initialize secondary processors.
85 * @todo move this into a method of per cpu data structure.
87 void secondary_cpu_init(void)
89 struct mem_range *mem;
93 atomic_inc(&active_cpus);
95 printk_debug("%s\n", __FUNCTION__);
97 id = cpu_initialize(mem);
98 index = processor_index(id);
99 printk_debug("%s %d/%u\n", __FUNCTION__ , index, id);
100 processor_map[index] = CPU_ENABLED;
102 atomic_dec(&active_cpus);
106 static void wait_for_other_cpus(void)
108 int old_active_count, active_count;
110 old_active_count = 1;
112 active_count = atomic_read(&active_cpus);
113 while (active_count > 1) {
114 if (active_count != old_active_count) {
115 printk_info("Waiting for %d CPUS to stop\n",
117 old_active_count = active_count;
119 active_count = atomic_read(&active_cpus);
122 for (i = 0; i < CONFIG_MAX_CPUS; i++) {
123 if (!(processor_map[i] & CPU_ENABLED)) {
124 printk_err("CPU %d did not initialize!\n", i);
125 processor_map[i] = 0;
129 printk_debug("All AP CPUs stopped\n");
132 #else /* CONIFG_SMP */
133 #define wait_for_other_cpus() do {} while(0)
134 #endif /* CONFIG_SMP */
137 * @brief Main program of LinuxBIOS
139 * @param boot_complete
141 void hardwaremain(int boot_complete)
143 /* Processor ID of the BOOT cpu (i.e. the one running this code) */
144 unsigned long boot_cpu;
146 struct mem_range *mem, *tmem;
147 struct lb_memory *lb_mem;
148 unsigned long totalmem;
152 CONFIGURE(CONF_PASS_PRE_CONSOLE);
154 /* displayinit MUST PRECEDE ALL PRINTK! */
158 printk_notice("LinuxBIOS-%s%s %s %s...\n",
159 linuxbios_version, linuxbios_extra_version,
160 linuxbios_build, (boot_complete)?"rebooting":"booting");
164 /* If we have already booted attempt a hard reboot */
169 CONFIGURE(CONF_PASS_PRE_PCI);
171 /* determine how software can generate PCI configuration transactions
173 printk_info("Finding PCI configuration type.\n");
177 /* convert static device structures into dynamic device structures
178 * before probing dynamic devices. */
179 enumerate_static_devices();
181 /* probe the existence of dynamic devices and construct the dynamic
186 /* probe and assign the resources required by the dynamic devices */
190 /* enable the resources probed and assigned in dev_configure() */
193 /* do the device specific init in additional to simple resources
194 * allocation performed in dev_enable() */
198 CONFIGURE(CONF_PASS_POST_PCI);
200 /* this is done last because some devices may 'steal' memory from
201 * the system during device initialization. */
204 for (totalmem = 0, tmem = mem; tmem->sizek; tmem++) {
205 totalmem += tmem->sizek;
207 /* Round to the nearest mega */
208 printk_info("totalram: %ldM\n", (totalmem + 512) >> 10);
210 /* fully initialize the boot processor */
211 boot_cpu = cpu_initialize(mem);
212 boot_index = processor_index(boot_cpu);
213 printk_spew("BOOT CPU is %d\n", boot_cpu);
214 processor_map[boot_index] = CPU_BOOTPROCESSOR|CPU_ENABLED;
216 /* start up other processors, it works like a pthread_create() or
217 * fork(), instead of running the initialization code for all devices
218 * as the boot processor, they start from secondary_cpu_init(), doing
219 * cpu initialization only. */
221 startup_other_cpus(processor_map);
223 /* like pthread_join() or wait(), wait other processors finishing
224 * their execution of secondary_cpu_init() and make certain we are
225 * the only cpu running in LinuxBIOS */
226 wait_for_other_cpus();
228 /* Now that we have collected all of our information, write our
229 * configuration tables. */
230 lb_mem = write_tables(mem, processor_map);
232 CONFIGURE(CONF_PASS_PRE_BOOT);
234 #if CONFIG_FS_STREAM == 1