blob: 6231d1167ed42b0e5cff4c81df9a224d19b6f7c0 [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#if 0
41#include <part/mainboard.h>
42#endif
Eric Biederman8ca8d762003-04-22 19:02:15 +000043#include <part/hard_reset.h>
Eric Biederman8ca8d762003-04-22 19:02:15 +000044#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 */
Eric Biederman9bdb4602003-09-01 23:17:58 +000061static unsigned long processor_map[CONFIG_MAX_CPUS];
Eric Biederman8ca8d762003-04-22 19:02:15 +000062
63static struct mem_range *get_ramsize(void)
64{
65 struct mem_range *mem = 0;
66 if (!mem) {
67 mem = sizeram();
68 }
69 if (!mem) {
Eric Biederman2c018fb2003-07-21 20:13:45 +000070 printk_emerg("No memory size information!\n");
71 for(;;) {
72 /* Ensure this loop is not optimized away */
73 asm volatile("":/* outputs */:/*inputs */ :"memory");
74 }
Eric Biederman8ca8d762003-04-22 19:02:15 +000075 }
76 return mem;
77}
78
79
Eric Biederman9b4336c2003-07-19 04:28:22 +000080#if CONFIG_SMP == 1
Eric Biederman8ca8d762003-04-22 19:02:15 +000081/* Number of cpus that are currently running in linuxbios */
82static atomic_t active_cpus = ATOMIC_INIT(1);
83
84void secondary_cpu_init(void)
85{
86 struct mem_range *mem;
87 unsigned long id;
88 int index;
89
90 atomic_inc(&active_cpus);
Ronald G. Minnich987fe0f2003-09-26 14:36:27 +000091 printk_debug("%s\n", __FUNCTION__);
Eric Biederman8ca8d762003-04-22 19:02:15 +000092 mem = get_ramsize();
93 id = cpu_initialize(mem);
94 index = processor_index(id);
Ronald G. Minnich987fe0f2003-09-26 14:36:27 +000095 printk_debug("%s %d/%u\n", __FUNCTION__ , index, id);
Eric Biederman8ca8d762003-04-22 19:02:15 +000096 processor_map[index] = CPU_ENABLED;
97 atomic_dec(&active_cpus);
98 stop_cpu(id);
99}
100
101static 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 }
Eric Biederman9bdb4602003-09-01 23:17:58 +0000115 for(i = 0; i < CONFIG_MAX_CPUS; i++) {
Eric Biederman8ca8d762003-04-22 19:02:15 +0000116 if (!(processor_map[i] & CPU_ENABLED)) {
Eric Biederman9b4336c2003-07-19 04:28:22 +0000117 printk_err("CPU %d did not initialize!\n", i);
Eric Biederman8ca8d762003-04-22 19:02:15 +0000118 processor_map[i] = 0;
Eric Biederman9b4336c2003-07-19 04:28:22 +0000119#warning "FIXME do I need a mainboard_cpu_fixup function?"
Eric Biederman8ca8d762003-04-22 19:02:15 +0000120 }
121 }
122 printk_debug("All AP CPUs stopped\n");
123}
124
Eric Biederman2c018fb2003-07-21 20:13:45 +0000125#else /* CONIFG_SMP */
Eric Biederman8ca8d762003-04-22 19:02:15 +0000126#define wait_for_other_cpus() do {} while(0)
Eric Biederman2c018fb2003-07-21 20:13:45 +0000127#endif /* CONFIG_SMP */
Eric Biederman8ca8d762003-04-22 19:02:15 +0000128
129void 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);
Greg Watson2910a2b2003-07-23 18:20:17 +0000148
149 CONFIGURE(CONF_PASS_PRE_CONSOLE);
150
Eric Biederman8ca8d762003-04-22 19:02:15 +0000151 /* 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
Eric Biederman8ca8d762003-04-22 19:02:15 +0000161 /* If we have already booted attempt a hard reboot */
162 if (boot_complete) {
163 hard_reset();
164 }
Greg Watson2910a2b2003-07-23 18:20:17 +0000165 CONFIGURE(CONF_PASS_PRE_PCI);
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);
Eric Biederman8ca8d762003-04-22 19:02:15 +0000171 enumerate_static_devices();
Eric Biederman8ca8d762003-04-22 19:02:15 +0000172 dev_enumerate();
173 post_code(0x66);
Eric Biederman52685572003-05-19 19:16:21 +0000174 /* 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 */
Eric Biederman8ca8d762003-04-22 19:02:15 +0000178 dev_configure();
179 post_code(0x88);
180
181 dev_enable();
Eric Biederman52685572003-05-19 19:16:21 +0000182
Eric Biederman8ca8d762003-04-22 19:02:15 +0000183 dev_initialize();
184 post_code(0x89);
Eric Biederman8ca8d762003-04-22 19:02:15 +0000185
Greg Watson5bed9792003-07-23 21:38:02 +0000186 CONFIGURE(CONF_PASS_POST_PCI);
187
Eric Biederman8ca8d762003-04-22 19:02:15 +0000188 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
Greg Watson5bed9792003-07-23 21:38:02 +0000218 CONFIGURE(CONF_PASS_PRE_BOOT);
Greg Watson2910a2b2003-07-23 18:20:17 +0000219
Eric Biederman8ca8d762003-04-22 19:02:15 +0000220 elfboot(lb_mem);
221}
222