blob: e3667cccd89c7d32a7a7807f15991e6eeada4662 [file] [log] [blame]
Eric Biederman8ca8d762003-04-22 19:02:15 +00001/*
2This software and ancillary information (herein called SOFTWARE )
3called LinuxBIOS is made available under the terms described
4here. The SOFTWARE has been approved for release with associated
5LA-CC Number 00-34 . Unless otherwise indicated, this SOFTWARE has
6been authored by an employee or employees of the University of
7California, operator of the Los Alamos National Laboratory under
8Contract No. W-7405-ENG-36 with the U.S. Department of Energy. The
9U.S. Government has rights to use, reproduce, and distribute this
10SOFTWARE. The public may copy, distribute, prepare derivative works
11and publicly display this SOFTWARE without charge, provided that this
12Notice and any statement of authorship are reproduced on all copies.
13Neither the Government nor the University makes any warranty, express
14or implied, or assumes any liability or responsibility for the use of
15this SOFTWARE. If SOFTWARE is modified to produce derivative works,
16such modified SOFTWARE should be clearly marked, so as not to confuse
17it with the version available from LANL.
18 */
19/* Copyright 2000, Ron Minnich, Advanced Computing Lab, LANL
20 * rminnich@lanl.gov
21 */
22
23
24/*
25 * C Bootstrap code for the LinuxBIOS
26 */
27
28
29#include <console/console.h>
30#include <cpu/cpu.h>
31#include <mem.h>
32#include <version.h>
33#include <smp/start_stop.h>
34#include <boot/tables.h>
35#include <part/sizeram.h>
Eric Biederman5899fd82003-04-24 06:25:08 +000036#include <device/device.h>
37#include <device/pci.h>
Greg Watson2910a2b2003-07-23 18:20:17 +000038#include <device/chip.h>
Eric Biederman9b4336c2003-07-19 04:28:22 +000039#include <delay.h>
Eric Biederman8ca8d762003-04-22 19:02:15 +000040#include <part/hard_reset.h>
Eric Biederman8ca8d762003-04-22 19:02:15 +000041#include <smp/atomic.h>
42#include <boot/elf.h>
43
44
45#ifndef CONFIG_MAX_PHYSICAL_CPUS
46#define CONFIG_MAX_PHYSICAL_CPUS CONFIG_MAX_CPUS
47#endif
48
49/* The processor map.
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.
57 */
Eric Biederman9bdb4602003-09-01 23:17:58 +000058static unsigned long processor_map[CONFIG_MAX_CPUS];
Eric Biederman8ca8d762003-04-22 19:02:15 +000059
60static struct mem_range *get_ramsize(void)
61{
62 struct mem_range *mem = 0;
63 if (!mem) {
64 mem = sizeram();
65 }
66 if (!mem) {
Eric Biederman2c018fb2003-07-21 20:13:45 +000067 printk_emerg("No memory size information!\n");
68 for(;;) {
69 /* Ensure this loop is not optimized away */
70 asm volatile("":/* outputs */:/*inputs */ :"memory");
71 }
Eric Biederman8ca8d762003-04-22 19:02:15 +000072 }
73 return mem;
74}
75
76
Eric Biederman9b4336c2003-07-19 04:28:22 +000077#if CONFIG_SMP == 1
Eric Biederman8ca8d762003-04-22 19:02:15 +000078/* Number of cpus that are currently running in linuxbios */
79static atomic_t active_cpus = ATOMIC_INIT(1);
80
Li-Ta Loe5266692004-03-23 21:28:05 +000081/**
82 * @brief Initialize secondary processors.
83 *
84 *
85 * @todo move this into a method of per cpu data structure.
86 */
Eric Biederman8ca8d762003-04-22 19:02:15 +000087void secondary_cpu_init(void)
88{
89 struct mem_range *mem;
90 unsigned long id;
91 int index;
92
93 atomic_inc(&active_cpus);
Li-Ta Loe5266692004-03-23 21:28:05 +000094
Ronald G. Minnich987fe0f2003-09-26 14:36:27 +000095 printk_debug("%s\n", __FUNCTION__);
Eric Biederman8ca8d762003-04-22 19:02:15 +000096 mem = get_ramsize();
97 id = cpu_initialize(mem);
98 index = processor_index(id);
Ronald G. Minnich987fe0f2003-09-26 14:36:27 +000099 printk_debug("%s %d/%u\n", __FUNCTION__ , index, id);
Eric Biederman8ca8d762003-04-22 19:02:15 +0000100 processor_map[index] = CPU_ENABLED;
Li-Ta Loe5266692004-03-23 21:28:05 +0000101
Eric Biederman8ca8d762003-04-22 19:02:15 +0000102 atomic_dec(&active_cpus);
103 stop_cpu(id);
104}
105
106static void wait_for_other_cpus(void)
107{
108 int old_active_count, active_count;
109 int i;
110 old_active_count = 1;
111
112 active_count = atomic_read(&active_cpus);
Li-Ta Loe5266692004-03-23 21:28:05 +0000113 while (active_count > 1) {
Eric Biederman8ca8d762003-04-22 19:02:15 +0000114 if (active_count != old_active_count) {
Li-Ta Loe5266692004-03-23 21:28:05 +0000115 printk_info("Waiting for %d CPUS to stop\n",
116 active_count);
Eric Biederman8ca8d762003-04-22 19:02:15 +0000117 old_active_count = active_count;
118 }
119 active_count = atomic_read(&active_cpus);
120 }
Li-Ta Loe5266692004-03-23 21:28:05 +0000121
122 for (i = 0; i < CONFIG_MAX_CPUS; i++) {
Eric Biederman8ca8d762003-04-22 19:02:15 +0000123 if (!(processor_map[i] & CPU_ENABLED)) {
Eric Biederman9b4336c2003-07-19 04:28:22 +0000124 printk_err("CPU %d did not initialize!\n", i);
Eric Biederman8ca8d762003-04-22 19:02:15 +0000125 processor_map[i] = 0;
Eric Biederman8ca8d762003-04-22 19:02:15 +0000126 }
127 }
Li-Ta Loe5266692004-03-23 21:28:05 +0000128
Eric Biederman8ca8d762003-04-22 19:02:15 +0000129 printk_debug("All AP CPUs stopped\n");
130}
131
Eric Biederman2c018fb2003-07-21 20:13:45 +0000132#else /* CONIFG_SMP */
Eric Biederman8ca8d762003-04-22 19:02:15 +0000133#define wait_for_other_cpus() do {} while(0)
Eric Biederman2c018fb2003-07-21 20:13:45 +0000134#endif /* CONFIG_SMP */
Eric Biederman8ca8d762003-04-22 19:02:15 +0000135
Li-Ta Loe5266692004-03-23 21:28:05 +0000136/**
137 * @brief Main program of LinuxBIOS
138 *
139 * @param boot_complete
140 */
Eric Biederman8ca8d762003-04-22 19:02:15 +0000141void hardwaremain(int boot_complete)
142{
143 /* Processor ID of the BOOT cpu (i.e. the one running this code) */
144 unsigned long boot_cpu;
145 int boot_index;
Eric Biederman8ca8d762003-04-22 19:02:15 +0000146 struct mem_range *mem, *tmem;
147 struct lb_memory *lb_mem;
148 unsigned long totalmem;
149
150 post_code(0x80);
Greg Watson2910a2b2003-07-23 18:20:17 +0000151
152 CONFIGURE(CONF_PASS_PRE_CONSOLE);
153
Eric Biederman8ca8d762003-04-22 19:02:15 +0000154 /* displayinit MUST PRECEDE ALL PRINTK! */
155 console_init();
156
157 post_code(0x39);
158 printk_notice("LinuxBIOS-%s%s %s %s...\n",
Li-Ta Loe5266692004-03-23 21:28:05 +0000159 linuxbios_version, linuxbios_extra_version,
160 linuxbios_build, (boot_complete)?"rebooting":"booting");
Eric Biederman8ca8d762003-04-22 19:02:15 +0000161
162 post_code(0x40);
163
Eric Biederman8ca8d762003-04-22 19:02:15 +0000164 /* If we have already booted attempt a hard reboot */
165 if (boot_complete) {
166 hard_reset();
167 }
Li-Ta Loe5266692004-03-23 21:28:05 +0000168
Greg Watson2910a2b2003-07-23 18:20:17 +0000169 CONFIGURE(CONF_PASS_PRE_PCI);
Eric Biederman8ca8d762003-04-22 19:02:15 +0000170
Li-Ta Loe5266692004-03-23 21:28:05 +0000171 /* determine how software can generate PCI configuration transactions
172 * in this system */
Eric Biederman8ca8d762003-04-22 19:02:15 +0000173 printk_info("Finding PCI configuration type.\n");
174 pci_set_method();
175 post_code(0x5f);
Li-Ta Loe5266692004-03-23 21:28:05 +0000176
177 /* convert static device structures into dynamic device structures
178 * before probing dynamic devices. */
Eric Biederman8ca8d762003-04-22 19:02:15 +0000179 enumerate_static_devices();
Li-Ta Loe5266692004-03-23 21:28:05 +0000180
181 /* probe the existence of dynamic devices and construct the dynamic
182 * device tree. */
Eric Biederman8ca8d762003-04-22 19:02:15 +0000183 dev_enumerate();
184 post_code(0x66);
Li-Ta Loe5266692004-03-23 21:28:05 +0000185
186 /* probe and assign the resources required by the dynamic devices */
Eric Biederman8ca8d762003-04-22 19:02:15 +0000187 dev_configure();
188 post_code(0x88);
189
Li-Ta Loe5266692004-03-23 21:28:05 +0000190 /* enable the resources probed and assigned in dev_configure() */
Eric Biederman8ca8d762003-04-22 19:02:15 +0000191 dev_enable();
Eric Biederman52685572003-05-19 19:16:21 +0000192
Li-Ta Loe5266692004-03-23 21:28:05 +0000193 /* do the device specific init in additional to simple resources
194 * allocation performed in dev_enable() */
Eric Biederman8ca8d762003-04-22 19:02:15 +0000195 dev_initialize();
196 post_code(0x89);
Eric Biederman8ca8d762003-04-22 19:02:15 +0000197
Greg Watson5bed9792003-07-23 21:38:02 +0000198 CONFIGURE(CONF_PASS_POST_PCI);
199
Li-Ta Loe5266692004-03-23 21:28:05 +0000200 /* this is done last because some devices may 'steal' memory from
201 * the system during device initialization. */
Eric Biederman8ca8d762003-04-22 19:02:15 +0000202 mem = get_ramsize();
203 post_code(0x70);
Li-Ta Loe5266692004-03-23 21:28:05 +0000204 for (totalmem = 0, tmem = mem; tmem->sizek; tmem++) {
Eric Biederman8ca8d762003-04-22 19:02:15 +0000205 totalmem += tmem->sizek;
206 }
Li-Ta Loe5266692004-03-23 21:28:05 +0000207 /* Round to the nearest mega */
208 printk_info("totalram: %ldM\n", (totalmem + 512) >> 10);
Eric Biederman8ca8d762003-04-22 19:02:15 +0000209
Li-Ta Loe5266692004-03-23 21:28:05 +0000210 /* fully initialize the boot processor */
Eric Biederman8ca8d762003-04-22 19:02:15 +0000211 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;
215
Li-Ta Loe5266692004-03-23 21:28:05 +0000216 /* 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. */
Eric Biederman8ca8d762003-04-22 19:02:15 +0000220 post_code(0x75);
221 startup_other_cpus(processor_map);
Eric Biederman8ca8d762003-04-22 19:02:15 +0000222
Li-Ta Loe5266692004-03-23 21:28:05 +0000223 /* 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 */
Eric Biederman8ca8d762003-04-22 19:02:15 +0000226 wait_for_other_cpus();
227
Li-Ta Loe5266692004-03-23 21:28:05 +0000228 /* Now that we have collected all of our information, write our
229 * configuration tables. */
Eric Biederman8ca8d762003-04-22 19:02:15 +0000230 lb_mem = write_tables(mem, processor_map);
231
Greg Watson5bed9792003-07-23 21:38:02 +0000232 CONFIGURE(CONF_PASS_PRE_BOOT);
Greg Watson2910a2b2003-07-23 18:20:17 +0000233
Greg Watson9cfecd12004-03-17 17:10:32 +0000234#if CONFIG_FS_STREAM == 1
235 filo(lb_mem);
236#else
Eric Biederman8ca8d762003-04-22 19:02:15 +0000237 elfboot(lb_mem);
Greg Watson9cfecd12004-03-17 17:10:32 +0000238#endif
Eric Biederman8ca8d762003-04-22 19:02:15 +0000239}
240