blob: efaf59519d5e9cf21410f12459f401845af7fe48 [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
Greg Watson23e2e182004-03-26 02:32:45 +000049#if CONFIG_FS_STREAM == 1
50extern int filo(struct lb_memory *);
51#endif
52
Eric Biederman8ca8d762003-04-22 19:02:15 +000053/* The processor map.
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.
61 */
Eric Biederman9bdb4602003-09-01 23:17:58 +000062static unsigned long processor_map[CONFIG_MAX_CPUS];
Eric Biederman8ca8d762003-04-22 19:02:15 +000063
64static struct mem_range *get_ramsize(void)
65{
66 struct mem_range *mem = 0;
67 if (!mem) {
68 mem = sizeram();
69 }
70 if (!mem) {
Eric Biederman2c018fb2003-07-21 20:13:45 +000071 printk_emerg("No memory size information!\n");
72 for(;;) {
73 /* Ensure this loop is not optimized away */
74 asm volatile("":/* outputs */:/*inputs */ :"memory");
75 }
Eric Biederman8ca8d762003-04-22 19:02:15 +000076 }
77 return mem;
78}
79
80
Eric Biederman9b4336c2003-07-19 04:28:22 +000081#if CONFIG_SMP == 1
Eric Biederman8ca8d762003-04-22 19:02:15 +000082/* Number of cpus that are currently running in linuxbios */
83static atomic_t active_cpus = ATOMIC_INIT(1);
84
Li-Ta Loe5266692004-03-23 21:28:05 +000085/**
86 * @brief Initialize secondary processors.
87 *
88 *
89 * @todo move this into a method of per cpu data structure.
90 */
Eric Biederman8ca8d762003-04-22 19:02:15 +000091void secondary_cpu_init(void)
92{
93 struct mem_range *mem;
94 unsigned long id;
95 int index;
96
97 atomic_inc(&active_cpus);
Li-Ta Loe5266692004-03-23 21:28:05 +000098
Ronald G. Minnich987fe0f2003-09-26 14:36:27 +000099 printk_debug("%s\n", __FUNCTION__);
Eric Biederman8ca8d762003-04-22 19:02:15 +0000100 mem = get_ramsize();
101 id = cpu_initialize(mem);
102 index = processor_index(id);
Ronald G. Minnich987fe0f2003-09-26 14:36:27 +0000103 printk_debug("%s %d/%u\n", __FUNCTION__ , index, id);
Eric Biederman8ca8d762003-04-22 19:02:15 +0000104 processor_map[index] = CPU_ENABLED;
Li-Ta Loe5266692004-03-23 21:28:05 +0000105
Eric Biederman8ca8d762003-04-22 19:02:15 +0000106 atomic_dec(&active_cpus);
107 stop_cpu(id);
108}
109
110static void wait_for_other_cpus(void)
111{
112 int old_active_count, active_count;
113 int i;
114 old_active_count = 1;
115
116 active_count = atomic_read(&active_cpus);
Li-Ta Loe5266692004-03-23 21:28:05 +0000117 while (active_count > 1) {
Eric Biederman8ca8d762003-04-22 19:02:15 +0000118 if (active_count != old_active_count) {
Li-Ta Loe5266692004-03-23 21:28:05 +0000119 printk_info("Waiting for %d CPUS to stop\n",
120 active_count);
Eric Biederman8ca8d762003-04-22 19:02:15 +0000121 old_active_count = active_count;
122 }
123 active_count = atomic_read(&active_cpus);
124 }
Li-Ta Loe5266692004-03-23 21:28:05 +0000125
126 for (i = 0; i < CONFIG_MAX_CPUS; i++) {
Eric Biederman8ca8d762003-04-22 19:02:15 +0000127 if (!(processor_map[i] & CPU_ENABLED)) {
Eric Biederman9b4336c2003-07-19 04:28:22 +0000128 printk_err("CPU %d did not initialize!\n", i);
Eric Biederman8ca8d762003-04-22 19:02:15 +0000129 processor_map[i] = 0;
Eric Biederman8ca8d762003-04-22 19:02:15 +0000130 }
131 }
Li-Ta Loe5266692004-03-23 21:28:05 +0000132
Eric Biederman8ca8d762003-04-22 19:02:15 +0000133 printk_debug("All AP CPUs stopped\n");
134}
135
Eric Biederman2c018fb2003-07-21 20:13:45 +0000136#else /* CONIFG_SMP */
Eric Biederman8ca8d762003-04-22 19:02:15 +0000137#define wait_for_other_cpus() do {} while(0)
Eric Biederman2c018fb2003-07-21 20:13:45 +0000138#endif /* CONFIG_SMP */
Eric Biederman8ca8d762003-04-22 19:02:15 +0000139
Li-Ta Loe5266692004-03-23 21:28:05 +0000140/**
141 * @brief Main program of LinuxBIOS
142 *
143 * @param boot_complete
144 */
Eric Biederman8ca8d762003-04-22 19:02:15 +0000145void hardwaremain(int boot_complete)
146{
147 /* Processor ID of the BOOT cpu (i.e. the one running this code) */
148 unsigned long boot_cpu;
149 int boot_index;
Eric Biederman8ca8d762003-04-22 19:02:15 +0000150 struct mem_range *mem, *tmem;
151 struct lb_memory *lb_mem;
152 unsigned long totalmem;
153
154 post_code(0x80);
Li-Ta Lo6a8745ae2004-05-13 20:39:07 +0000155
Greg Watson2910a2b2003-07-23 18:20:17 +0000156 CONFIGURE(CONF_PASS_PRE_CONSOLE);
157
Eric Biederman8ca8d762003-04-22 19:02:15 +0000158 /* displayinit MUST PRECEDE ALL PRINTK! */
159 console_init();
160
161 post_code(0x39);
162 printk_notice("LinuxBIOS-%s%s %s %s...\n",
Li-Ta Loe5266692004-03-23 21:28:05 +0000163 linuxbios_version, linuxbios_extra_version,
164 linuxbios_build, (boot_complete)?"rebooting":"booting");
Eric Biederman8ca8d762003-04-22 19:02:15 +0000165
166 post_code(0x40);
167
Eric Biederman8ca8d762003-04-22 19:02:15 +0000168 /* If we have already booted attempt a hard reboot */
169 if (boot_complete) {
170 hard_reset();
171 }
Li-Ta Loe5266692004-03-23 21:28:05 +0000172
Greg Watson2910a2b2003-07-23 18:20:17 +0000173 CONFIGURE(CONF_PASS_PRE_PCI);
Eric Biederman8ca8d762003-04-22 19:02:15 +0000174
Li-Ta Loe5266692004-03-23 21:28:05 +0000175 /* determine how software can generate PCI configuration transactions
176 * in this system */
Eric Biederman8ca8d762003-04-22 19:02:15 +0000177 printk_info("Finding PCI configuration type.\n");
178 pci_set_method();
179 post_code(0x5f);
Li-Ta Loe5266692004-03-23 21:28:05 +0000180
181 /* convert static device structures into dynamic device structures
182 * before probing dynamic devices. */
Eric Biederman8ca8d762003-04-22 19:02:15 +0000183 enumerate_static_devices();
Li-Ta Loe5266692004-03-23 21:28:05 +0000184
185 /* probe the existence of dynamic devices and construct the dynamic
186 * device tree. */
Eric Biederman8ca8d762003-04-22 19:02:15 +0000187 dev_enumerate();
188 post_code(0x66);
Li-Ta Loe5266692004-03-23 21:28:05 +0000189
190 /* probe and assign the resources required by the dynamic devices */
Eric Biederman8ca8d762003-04-22 19:02:15 +0000191 dev_configure();
192 post_code(0x88);
193
Li-Ta Loe5266692004-03-23 21:28:05 +0000194 /* enable the resources probed and assigned in dev_configure() */
Eric Biederman8ca8d762003-04-22 19:02:15 +0000195 dev_enable();
Eric Biederman52685572003-05-19 19:16:21 +0000196
Li-Ta Loe5266692004-03-23 21:28:05 +0000197 /* do the device specific init in additional to simple resources
198 * allocation performed in dev_enable() */
Eric Biederman8ca8d762003-04-22 19:02:15 +0000199 dev_initialize();
200 post_code(0x89);
Eric Biederman8ca8d762003-04-22 19:02:15 +0000201
Greg Watson5bed9792003-07-23 21:38:02 +0000202 CONFIGURE(CONF_PASS_POST_PCI);
203
Li-Ta Loe5266692004-03-23 21:28:05 +0000204 /* this is done last because some devices may 'steal' memory from
205 * the system during device initialization. */
Eric Biederman8ca8d762003-04-22 19:02:15 +0000206 mem = get_ramsize();
207 post_code(0x70);
Li-Ta Loe5266692004-03-23 21:28:05 +0000208 for (totalmem = 0, tmem = mem; tmem->sizek; tmem++) {
Eric Biederman8ca8d762003-04-22 19:02:15 +0000209 totalmem += tmem->sizek;
210 }
Li-Ta Loe5266692004-03-23 21:28:05 +0000211 /* Round to the nearest mega */
212 printk_info("totalram: %ldM\n", (totalmem + 512) >> 10);
Eric Biederman8ca8d762003-04-22 19:02:15 +0000213
Li-Ta Loe5266692004-03-23 21:28:05 +0000214 /* fully initialize the boot processor */
Eric Biederman8ca8d762003-04-22 19:02:15 +0000215 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;
219
Li-Ta Loe5266692004-03-23 21:28:05 +0000220 /* 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. */
Eric Biederman8ca8d762003-04-22 19:02:15 +0000224 post_code(0x75);
225 startup_other_cpus(processor_map);
Eric Biederman8ca8d762003-04-22 19:02:15 +0000226
Li-Ta Loe5266692004-03-23 21:28:05 +0000227 /* 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 */
Eric Biederman8ca8d762003-04-22 19:02:15 +0000230 wait_for_other_cpus();
231
Li-Ta Loe5266692004-03-23 21:28:05 +0000232 /* Now that we have collected all of our information, write our
233 * configuration tables. */
Eric Biederman8ca8d762003-04-22 19:02:15 +0000234 lb_mem = write_tables(mem, processor_map);
235
Greg Watson5bed9792003-07-23 21:38:02 +0000236 CONFIGURE(CONF_PASS_PRE_BOOT);
Greg Watson2910a2b2003-07-23 18:20:17 +0000237
Greg Watson9cfecd12004-03-17 17:10:32 +0000238#if CONFIG_FS_STREAM == 1
239 filo(lb_mem);
240#else
Eric Biederman8ca8d762003-04-22 19:02:15 +0000241 elfboot(lb_mem);
Greg Watson9cfecd12004-03-17 17:10:32 +0000242#endif
Eric Biederman8ca8d762003-04-22 19:02:15 +0000243}
244