/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- mips_timer_set
- mainbus_bootstrap
- mainbus_start_cpus
- lamebus_map_area
- lamebus_read_register
- lamebus_write_register
- mainbus_poweroff
- mainbus_reboot
- mainbus_halt
- mainbus_panic
- mainbus_ramsize
- mainbus_send_ipi
- mainbus_interrupt
1 /*
2 * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
3 * The President and Fellows of Harvard College.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 #include <types.h>
31 #include <kern/unistd.h>
32 #include <lib.h>
33 #include <mips/trapframe.h>
34 #include <cpu.h>
35 #include <spl.h>
36 #include <clock.h>
37 #include <thread.h>
38 #include <current.h>
39 #include <synch.h>
40 #include <mainbus.h>
41 #include <sys161/bus.h>
42 #include <lamebus/lamebus.h>
43 #include "autoconf.h"
44
45 /*
46 * CPU frequency used by the on-chip timer.
47 *
48 * Note that we really ought to measure the CPU frequency against the
49 * real-time clock instead of compiling it in like this.
50 */
51 #define CPU_FREQUENCY 25000000 /* 25 MHz */
52
53 /*
54 * Access to the on-chip timer.
55 *
56 * The c0_count register increments on every cycle; when the value
57 * matches the c0_compare register, the timer interrupt line is
58 * asserted. Writing to c0_compare again clears the interrupt.
59 */
60 static
61 void
62 mips_timer_set(uint32_t count)
63 {
64 /*
65 * $11 == c0_compare; we can't use the symbolic name inside
66 * the asm string.
67 */
68 __asm volatile(
69 ".set push;" /* save assembler mode */
70 ".set mips32;" /* allow MIPS32 registers */
71 "mtc0 %0, $11;" /* do it */
72 ".set pop" /* restore assembler mode */
73 :: "r" (count));
74 }
75
76 /*
77 * LAMEbus data for the system. (We have only one LAMEbus per system.)
78 * This does not need to be locked, because it's constant once
79 * initialized, and initialized before we start other threads or CPUs.
80 */
81 static struct lamebus_softc *lamebus;
82
83 void
84 mainbus_bootstrap(void)
85 {
86 /* Interrupts should be off (and have been off since startup) */
87 KASSERT(curthread->t_curspl > 0);
88
89 /* Initialize the system LAMEbus data */
90 lamebus = lamebus_init();
91
92 /* Probe CPUs (should these be done as device attachments instead?) */
93 lamebus_find_cpus(lamebus);
94
95 /*
96 * Print the device name for the main bus.
97 */
98 kprintf("lamebus0 (system main bus)\n");
99
100 /*
101 * Now we can take interrupts without croaking, so turn them on.
102 * Some device probes might require being able to get interrupts.
103 */
104
105 spl0();
106
107 /*
108 * Now probe all the devices attached to the bus.
109 * (This amounts to all devices.)
110 */
111 autoconf_lamebus(lamebus, 0);
112
113 /*
114 * Configure the MIPS on-chip timer to interrupt HZ times a second.
115 */
116 mips_timer_set(CPU_FREQUENCY / HZ);
117 }
118
119 /*
120 * Start all secondary CPUs.
121 */
122 void
123 mainbus_start_cpus(void)
124 {
125 lamebus_start_cpus(lamebus);
126 }
127
128 /*
129 * Function to generate the memory address (in the uncached segment)
130 * for the specified offset into the specified slot's region of the
131 * LAMEbus.
132 */
133 void *
134 lamebus_map_area(struct lamebus_softc *bus, int slot, uint32_t offset)
135 {
136 uint32_t address;
137
138 (void)bus; // not needed
139
140 KASSERT(slot >= 0 && slot < LB_NSLOTS);
141
142 address = LB_BASEADDR + slot*LB_SLOT_SIZE + offset;
143 return (void *)address;
144 }
145
146 /*
147 * Read a 32-bit register from a LAMEbus device.
148 */
149 uint32_t
150 lamebus_read_register(struct lamebus_softc *bus, int slot, uint32_t offset)
151 {
152 uint32_t *ptr = lamebus_map_area(bus, slot, offset);
153
154 return *ptr;
155 }
156
157 /*
158 * Write a 32-bit register of a LAMEbus device.
159 */
160 void
161 lamebus_write_register(struct lamebus_softc *bus, int slot,
162 uint32_t offset, uint32_t val)
163 {
164 uint32_t *ptr = lamebus_map_area(bus, slot, offset);
165
166 *ptr = val;
167 }
168
169
170 /*
171 * Power off the system.
172 */
173 void
174 mainbus_poweroff(void)
175 {
176 /*
177 *
178 * Note that lamebus_write_register() doesn't actually access
179 * the bus argument, so this will still work if we get here
180 * before the bus is initialized.
181 */
182 lamebus_poweroff(lamebus);
183 }
184
185 /*
186 * Reboot the system.
187 */
188 void
189 mainbus_reboot(void)
190 {
191 /*
192 * The MIPS doesn't appear to have any on-chip reset.
193 * LAMEbus doesn't have a reset control, so we just
194 * power off instead of rebooting. This would not be
195 * so great in a real system, but it's fine for what
196 * we're doing.
197 */
198 kprintf("Cannot reboot - powering off instead, sorry.\n");
199 mainbus_poweroff();
200 }
201
202 /*
203 * Halt the system.
204 * On some systems, this would return to the boot monitor. But we don't
205 * have one.
206 */
207 void
208 mainbus_halt(void)
209 {
210 cpu_halt();
211 }
212
213 /*
214 * Called to reset the system from panic().
215 *
216 * By the time we get here, the system may well be sufficiently hosed
217 * as to panic recursively if we do much of anything. So just power off.
218 * (We'd reboot, but System/161 doesn't do that.)
219 */
220 void
221 mainbus_panic(void)
222 {
223 mainbus_poweroff();
224 }
225
226 /*
227 * Function to get the size of installed physical RAM from the LAMEbus
228 * controller.
229 */
230 uint32_t
231 mainbus_ramsize(void)
232 {
233 return lamebus_ramsize();
234 }
235
236 /*
237 * Send IPI.
238 */
239 void
240 mainbus_send_ipi(struct cpu *target)
241 {
242 lamebus_assert_ipi(lamebus, target);
243 }
244
245 /*
246 * Interrupt dispatcher.
247 */
248
249 /* Wiring of LAMEbus interrupts to bits in the cause register */
250 #define LAMEBUS_IRQ_BIT 0x00000400 /* all system bus slots */
251 #define LAMEBUS_IPI_BIT 0x00000800 /* inter-processor interrupt */
252 #define MIPS_TIMER_BIT 0x00008000 /* on-chip timer */
253
254 void
255 mainbus_interrupt(struct trapframe *tf)
256 {
257 uint32_t cause;
258
259 /* interrupts should be off */
260 KASSERT(curthread->t_curspl > 0);
261
262 cause = tf->tf_cause;
263 if (cause & LAMEBUS_IRQ_BIT) {
264 lamebus_interrupt(lamebus);
265 }
266 else if (cause & LAMEBUS_IPI_BIT) {
267 interprocessor_interrupt();
268 lamebus_clear_ipi(lamebus, curcpu);
269 }
270 else if (cause & MIPS_TIMER_BIT) {
271 /* Reset the timer (this clears the interrupt) */
272 mips_timer_set(CPU_FREQUENCY / HZ);
273 /* and call hardclock */
274 hardclock();
275 }
276 else {
277 panic("Unknown interrupt; cause register is %08x\n", cause);
278 }
279 }