blob: 0477253ec449ef689494bbe53784621bf565e5a9 [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>
Eric Biederman9b4336c2003-07-19 04:28:22 +000038#include <delay.h>
Eric Biederman8ca8d762003-04-22 19:02:15 +000039#if 0
40#include <part/mainboard.h>
41#endif
42#if 0
43#include <part/hard_reset.h>
44#endif
45#include <smp/atomic.h>
46#include <boot/elf.h>
47
48
49#ifndef CONFIG_MAX_PHYSICAL_CPUS
50#define CONFIG_MAX_PHYSICAL_CPUS CONFIG_MAX_CPUS
51#endif
52
53/* 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 */
62static unsigned long processor_map[MAX_CPUS];
63
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
85void secondary_cpu_init(void)
86{
87 struct mem_range *mem;
88 unsigned long id;
89 int index;
90
91 atomic_inc(&active_cpus);
92 printk_debug(__FUNCTION__ "\n");
93 mem = get_ramsize();
94 id = cpu_initialize(mem);
95 index = processor_index(id);
96 printk_debug(__FUNCTION__ " %d/%u\n", index, id);
97 processor_map[index] = CPU_ENABLED;
98 atomic_dec(&active_cpus);
99 stop_cpu(id);
100}
101
102static void wait_for_other_cpus(void)
103{
104 int old_active_count, active_count;
105 int i;
106 old_active_count = 1;
107
108 active_count = atomic_read(&active_cpus);
109 while(active_count > 1) {
110 if (active_count != old_active_count) {
111 printk_info("Waiting for %d CPUS to stop\n", active_count);
112 old_active_count = active_count;
113 }
114 active_count = atomic_read(&active_cpus);
115 }
116 for(i = 0; i < MAX_CPUS; i++) {
117 if (!(processor_map[i] & CPU_ENABLED)) {
Eric Biederman9b4336c2003-07-19 04:28:22 +0000118 printk_err("CPU %d did not initialize!\n", i);
Eric Biederman8ca8d762003-04-22 19:02:15 +0000119 processor_map[i] = 0;
Eric Biederman9b4336c2003-07-19 04:28:22 +0000120#warning "FIXME do I need a mainboard_cpu_fixup function?"
Eric Biederman8ca8d762003-04-22 19:02:15 +0000121 }
122 }
123 printk_debug("All AP CPUs stopped\n");
124}
125
Eric Biederman2c018fb2003-07-21 20:13:45 +0000126#else /* CONIFG_SMP */
Eric Biederman8ca8d762003-04-22 19:02:15 +0000127#define wait_for_other_cpus() do {} while(0)
Eric Biederman2c018fb2003-07-21 20:13:45 +0000128#endif /* CONFIG_SMP */
Eric Biederman8ca8d762003-04-22 19:02:15 +0000129
130void hardwaremain(int boot_complete)
131{
132 /* Processor ID of the BOOT cpu (i.e. the one running this code) */
133 unsigned long boot_cpu;
134 int boot_index;
135
136 /* the order here is a bit tricky. We don't want to do much of
137 * anything that uses config registers until after PciAllocateResources
138 * since that function also figures out what kind of config strategy
139 * to use (type 1 or type 2).
140 * so we turn on cache, then worry about PCI setup, then do other
141 * things, so that the other work can use the PciRead* and PciWrite*
142 * functions.
143 */
144 struct mem_range *mem, *tmem;
145 struct lb_memory *lb_mem;
146 unsigned long totalmem;
147
148 post_code(0x80);
149 /* displayinit MUST PRECEDE ALL PRINTK! */
150 console_init();
151
152 post_code(0x39);
153 printk_notice("LinuxBIOS-%s%s %s %s...\n",
154 linuxbios_version, linuxbios_extra_version, linuxbios_build,
155 (boot_complete)?"rebooting":"booting");
156
157 post_code(0x40);
158
159#if 0
160 /* If we have already booted attempt a hard reboot */
161 if (boot_complete) {
162 hard_reset();
163 }
164#endif
Eric Biederman9b4336c2003-07-19 04:28:22 +0000165 init_timer();
Eric Biederman8ca8d762003-04-22 19:02:15 +0000166
Eric Biederman52685572003-05-19 19:16:21 +0000167 /* pick how to scan the bus. This is first so we can get at memory size. */
Eric Biederman8ca8d762003-04-22 19:02:15 +0000168 printk_info("Finding PCI configuration type.\n");
169 pci_set_method();
170 post_code(0x5f);
171#if 0
172 enumerate_static_devices();
173#endif
174 dev_enumerate();
175 post_code(0x66);
Eric Biederman52685572003-05-19 19:16:21 +0000176 /* Now do the real bus.
177 * We round the total ram up a lot for thing like the SISFB, which
178 * shares high memory with the CPU.
179 */
Eric Biederman8ca8d762003-04-22 19:02:15 +0000180 dev_configure();
181 post_code(0x88);
182
183 dev_enable();
Eric Biederman52685572003-05-19 19:16:21 +0000184
Eric Biederman8ca8d762003-04-22 19:02:15 +0000185 dev_initialize();
186 post_code(0x89);
Eric Biederman8ca8d762003-04-22 19:02:15 +0000187
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 elfboot(lb_mem);
219}
220