fix 'deprecated' warnings
[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("%s\n", __FUNCTION__);
92         mem = get_ramsize();
93         id = cpu_initialize(mem);
94         index = processor_index(id);
95         printk_debug("%s  %d/%u\n", __FUNCTION__ , 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         CONFIGURE(CONF_PASS_PRE_PCI);
166
167         /* pick how to scan the bus. This is first so we can get at memory size. */
168         printk_info("Finding PCI configuration type.\n");
169         pci_set_method();
170         post_code(0x5f);
171         enumerate_static_devices();
172         dev_enumerate();
173         post_code(0x66);
174         /* Now do the real bus.
175          * We round the total ram up a lot for thing like the SISFB, which 
176          * shares high memory with the CPU. 
177          */
178         dev_configure();
179         post_code(0x88);
180
181         dev_enable();
182
183         dev_initialize();
184         post_code(0x89);
185
186         CONFIGURE(CONF_PASS_POST_PCI);
187
188         mem = get_ramsize();
189         post_code(0x70);
190         totalmem = 0;
191         for(tmem = mem; tmem->sizek; tmem++) {
192                 totalmem += tmem->sizek;
193         }
194         printk_info("totalram: %ldM\n", 
195                 (totalmem + 512) >> 10); /* Round to the nearest meg */
196
197         /* Fully initialize the cpu before configuring the bus */
198         boot_cpu = cpu_initialize(mem);
199         boot_index = processor_index(boot_cpu);
200         printk_spew("BOOT CPU is %d\n", boot_cpu);
201         processor_map[boot_index] = CPU_BOOTPROCESSOR|CPU_ENABLED;
202
203         /* Now start the other cpus initializing 
204          * The sooner they start the sooner they stop.
205          */
206         post_code(0x75);
207         startup_other_cpus(processor_map);
208         post_code(0x77);
209
210         /* make certain we are the only cpu running in linuxBIOS */
211         wait_for_other_cpus();
212
213         /* Now that we have collected all of our information
214          * write our configuration tables.
215          */
216         lb_mem = write_tables(mem, processor_map);
217
218         CONFIGURE(CONF_PASS_PRE_BOOT);
219
220         elfboot(lb_mem);
221 }
222