- Major update of the dynamic device tree so it can handle
[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 #if 0
41 #include <part/mainboard.h>
42 #endif
43 #include <part/hard_reset.h>
44 #include <smp/atomic.h>
45 #include <boot/elf.h>
46
47
48 #ifndef CONFIG_MAX_PHYSICAL_CPUS
49 #define CONFIG_MAX_PHYSICAL_CPUS CONFIG_MAX_CPUS
50 #endif
51
52 /* The processor map. 
53  * Now that SMP is in linuxbios, and Linux counts on us
54  * giving accurate information about processors, we need a map
55  * of what processors are out there. This could be a bit mask, 
56  * but we will be optimistic and hope we someday run on 
57  * REALLY BIG SMPs. Also we may need more than one bit of 
58  * info per processor at some point. I hope we don't need 
59  * anything more complex than an int.
60  */
61 static unsigned long processor_map[CONFIG_MAX_CPUS];
62
63 static struct mem_range *get_ramsize(void)
64 {
65         struct mem_range *mem = 0;
66         if (!mem) {
67                 mem = sizeram();
68         }
69         if (!mem) {
70                 printk_emerg("No memory size information!\n");
71                 for(;;) {
72                         /* Ensure this loop is not optimized away */
73                         asm volatile("":/* outputs */:/*inputs */ :"memory");
74                 }
75         }
76         return mem;
77 }
78
79
80 #if CONFIG_SMP == 1
81 /* Number of cpus that are currently running in linuxbios */
82 static atomic_t active_cpus = ATOMIC_INIT(1);
83
84 void secondary_cpu_init(void)
85 {
86         struct mem_range *mem;
87         unsigned long id;
88         int index;
89
90         atomic_inc(&active_cpus);
91         printk_debug(__FUNCTION__ "\n");
92         mem = get_ramsize();
93         id = cpu_initialize(mem);
94         index = processor_index(id);
95         printk_debug(__FUNCTION__ "  %d/%u\n", index, id);
96         processor_map[index] = CPU_ENABLED;
97         atomic_dec(&active_cpus);
98         stop_cpu(id);
99 }
100
101 static void wait_for_other_cpus(void)
102 {
103         int old_active_count, active_count;
104         int i;
105         old_active_count = 1;
106
107         active_count = atomic_read(&active_cpus);
108         while(active_count > 1) {
109                 if (active_count != old_active_count) {
110                         printk_info("Waiting for %d CPUS to stop\n", active_count);
111                         old_active_count = active_count;
112                 }
113                 active_count = atomic_read(&active_cpus);
114         }
115         for(i = 0; i < CONFIG_MAX_CPUS; i++) {
116                 if (!(processor_map[i] & CPU_ENABLED)) {
117                         printk_err("CPU %d did not initialize!\n", i);
118                         processor_map[i] = 0;
119 #warning "FIXME do I need a mainboard_cpu_fixup function?"
120                 }
121         }
122         printk_debug("All AP CPUs stopped\n");
123 }
124
125 #else /* CONIFG_SMP */
126 #define wait_for_other_cpus() do {} while(0)
127 #endif /* CONFIG_SMP */
128
129 void hardwaremain(int boot_complete)
130 {
131         /* Processor ID of the BOOT cpu (i.e. the one running this code) */
132         unsigned long boot_cpu;
133         int boot_index;
134
135         /* the order here is a bit tricky. We don't want to do much of 
136          * anything that uses config registers until after PciAllocateResources
137          * since that function also figures out what kind of config strategy
138          * to use (type 1 or type 2). 
139          * so we turn on cache, then worry about PCI setup, then do other 
140          * things, so that the other work can use the PciRead* and PciWrite*
141          * functions. 
142          */
143         struct mem_range *mem, *tmem;
144         struct lb_memory *lb_mem;
145         unsigned long totalmem;
146
147         post_code(0x80);
148         
149         CONFIGURE(CONF_PASS_PRE_CONSOLE);
150
151         /* displayinit MUST PRECEDE ALL PRINTK! */
152         console_init();
153         
154         post_code(0x39);
155         printk_notice("LinuxBIOS-%s%s %s %s...\n", 
156                 linuxbios_version, linuxbios_extra_version, linuxbios_build,
157                 (boot_complete)?"rebooting":"booting");
158
159         post_code(0x40);
160
161         /* If we have already booted attempt a hard reboot */
162         if (boot_complete) {
163                 hard_reset();
164         }
165         init_timer(); /* needs to be moved into static configuration */
166         CONFIGURE(CONF_PASS_PRE_PCI);
167
168         /* pick how to scan the bus. This is first so we can get at memory size. */
169         printk_info("Finding PCI configuration type.\n");
170         pci_set_method();
171         post_code(0x5f);
172         enumerate_static_devices();
173         dev_enumerate();
174         post_code(0x66);
175         /* Now do the real bus.
176          * We round the total ram up a lot for thing like the SISFB, which 
177          * shares high memory with the CPU. 
178          */
179         dev_configure();
180         post_code(0x88);
181
182         dev_enable();
183
184         dev_initialize();
185         post_code(0x89);
186
187         CONFIGURE(CONF_PASS_POST_PCI);
188
189         mem = get_ramsize();
190         post_code(0x70);
191         totalmem = 0;
192         for(tmem = mem; tmem->sizek; tmem++) {
193                 totalmem += tmem->sizek;
194         }
195         printk_info("totalram: %ldM\n", 
196                 (totalmem + 512) >> 10); /* Round to the nearest meg */
197
198         /* Fully initialize the cpu before configuring the bus */
199         boot_cpu = cpu_initialize(mem);
200         boot_index = processor_index(boot_cpu);
201         printk_spew("BOOT CPU is %d\n", boot_cpu);
202         processor_map[boot_index] = CPU_BOOTPROCESSOR|CPU_ENABLED;
203
204         /* Now start the other cpus initializing 
205          * The sooner they start the sooner they stop.
206          */
207         post_code(0x75);
208         startup_other_cpus(processor_map);
209         post_code(0x77);
210
211         /* make certain we are the only cpu running in linuxBIOS */
212         wait_for_other_cpus();
213
214         /* Now that we have collected all of our information
215          * write our configuration tables.
216          */
217         lb_mem = write_tables(mem, processor_map);
218
219         CONFIGURE(CONF_PASS_PRE_BOOT);
220
221         elfboot(lb_mem);
222 }
223