Doxidization, reformat
[coreboot.git] / src / boot / hardwaremain.c
1 /*
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.
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>
36 #include <device/device.h>
37 #include <device/pci.h>
38 #include <device/chip.h>
39 #include <delay.h>
40 #include <part/hard_reset.h>
41 #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  */
58 static unsigned long processor_map[CONFIG_MAX_CPUS];
59
60 static struct mem_range *get_ramsize(void)
61 {
62         struct mem_range *mem = 0;
63         if (!mem) {
64                 mem = sizeram();
65         }
66         if (!mem) {
67                 printk_emerg("No memory size information!\n");
68                 for(;;) {
69                         /* Ensure this loop is not optimized away */
70                         asm volatile("":/* outputs */:/*inputs */ :"memory");
71                 }
72         }
73         return mem;
74 }
75
76
77 #if CONFIG_SMP == 1
78 /* Number of cpus that are currently running in linuxbios */
79 static atomic_t active_cpus = ATOMIC_INIT(1);
80
81 /**
82  * @brief Initialize secondary processors.
83  *
84  *
85  * @todo move this into a method of per cpu data structure.
86  */
87 void secondary_cpu_init(void)
88 {
89         struct mem_range *mem;
90         unsigned long id;
91         int index;
92
93         atomic_inc(&active_cpus);
94
95         printk_debug("%s\n", __FUNCTION__);
96         mem = get_ramsize();
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;
101
102         atomic_dec(&active_cpus);
103         stop_cpu(id);
104 }
105
106 static 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);
113         while (active_count > 1) {
114                 if (active_count != old_active_count) {
115                         printk_info("Waiting for %d CPUS to stop\n",
116                                     active_count);
117                         old_active_count = active_count;
118                 }
119                 active_count = atomic_read(&active_cpus);
120         }
121
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;
126                 }
127         }
128
129         printk_debug("All AP CPUs stopped\n");
130 }
131
132 #else /* CONIFG_SMP */
133 #define wait_for_other_cpus() do {} while(0)
134 #endif /* CONFIG_SMP */
135
136 /**
137  * @brief Main program of LinuxBIOS
138  *
139  * @param boot_complete
140  */
141 void 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;
146         struct mem_range *mem, *tmem;
147         struct lb_memory *lb_mem;
148         unsigned long totalmem;
149
150         post_code(0x80);
151         
152         CONFIGURE(CONF_PASS_PRE_CONSOLE);
153
154         /* displayinit MUST PRECEDE ALL PRINTK! */
155         console_init();
156         
157         post_code(0x39);
158         printk_notice("LinuxBIOS-%s%s %s %s...\n", 
159                       linuxbios_version, linuxbios_extra_version,
160                       linuxbios_build, (boot_complete)?"rebooting":"booting");
161
162         post_code(0x40);
163
164         /* If we have already booted attempt a hard reboot */
165         if (boot_complete) {
166                 hard_reset();
167         }
168
169         CONFIGURE(CONF_PASS_PRE_PCI);
170
171         /* determine how software can generate PCI configuration transactions
172          * in this system  */
173         printk_info("Finding PCI configuration type.\n");
174         pci_set_method();
175         post_code(0x5f);
176
177         /* convert static device structures into dynamic device structures
178          * before probing dynamic devices. */
179         enumerate_static_devices();
180
181         /* probe the existence of dynamic devices and construct the dynamic
182          * device tree. */
183         dev_enumerate();
184         post_code(0x66);
185
186         /* probe and assign the resources required by the dynamic devices */
187         dev_configure();
188         post_code(0x88);
189
190         /* enable the resources probed and assigned in dev_configure() */
191         dev_enable();
192
193         /* do the device specific init in additional to simple resources
194          * allocation performed in dev_enable() */
195         dev_initialize();
196         post_code(0x89);
197
198         CONFIGURE(CONF_PASS_POST_PCI);
199
200         /* this is done last because some devices may 'steal' memory from
201          * the system during device initialization. */
202         mem = get_ramsize();
203         post_code(0x70);
204         for (totalmem = 0, tmem = mem; tmem->sizek; tmem++) {
205                 totalmem += tmem->sizek;
206         }
207         /* Round to the nearest mega */
208         printk_info("totalram: %ldM\n", (totalmem + 512) >> 10);
209
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;
215
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. */
220         post_code(0x75);
221         startup_other_cpus(processor_map);
222
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();
227
228         /* Now that we have collected all of our information, write our
229          * configuration tables. */
230         lb_mem = write_tables(mem, processor_map);
231
232         CONFIGURE(CONF_PASS_PRE_BOOT);
233
234 #if CONFIG_FS_STREAM == 1
235         filo(lb_mem);
236 #else
237         elfboot(lb_mem);
238 #endif
239 }
240