00001 /* 00002 * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 00003 * The President and Fellows of Harvard College. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions 00007 * are met: 00008 * 1. Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * 2. Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * 3. Neither the name of the University nor the names of its contributors 00014 * may be used to endorse or promote products derived from this software 00015 * without specific prior written permission. 00016 * 00017 * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND 00018 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00019 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00020 * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE 00021 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00022 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 00023 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00024 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00025 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 00026 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 00027 * SUCH DAMAGE. 00028 */ 00029 00030 #include <types.h> 00031 #include <kern/unistd.h> 00032 #include <lib.h> 00033 #include <mips/trapframe.h> 00034 #include <cpu.h> 00035 #include <spl.h> 00036 #include <clock.h> 00037 #include <thread.h> 00038 #include <current.h> 00039 #include <synch.h> 00040 #include <mainbus.h> 00041 #include <sys161/bus.h> 00042 #include <lamebus/lamebus.h> 00043 #include "autoconf.h" 00044 00045 /* 00046 * CPU frequency used by the on-chip timer. 00047 * 00048 * Note that we really ought to measure the CPU frequency against the 00049 * real-time clock instead of compiling it in like this. 00050 */ 00051 #define CPU_FREQUENCY 25000000 /* 25 MHz */ 00052 00053 /* 00054 * Access to the on-chip timer. 00055 * 00056 * The c0_count register increments on every cycle; when the value 00057 * matches the c0_compare register, the timer interrupt line is 00058 * asserted. Writing to c0_compare again clears the interrupt. 00059 */ 00060 static 00061 void 00062 mips_timer_set(uint32_t count) 00063 { 00064 /* 00065 * $11 == c0_compare; we can't use the symbolic name inside 00066 * the asm string. 00067 */ 00068 __asm volatile( 00069 ".set push;" /* save assembler mode */ 00070 ".set mips32;" /* allow MIPS32 registers */ 00071 "mtc0 %0, $11;" /* do it */ 00072 ".set pop" /* restore assembler mode */ 00073 :: "r" (count)); 00074 } 00075 00076 /* 00077 * LAMEbus data for the system. (We have only one LAMEbus per system.) 00078 * This does not need to be locked, because it's constant once 00079 * initialized, and initialized before we start other threads or CPUs. 00080 */ 00081 static struct lamebus_softc *lamebus; 00082 00083 void 00084 mainbus_bootstrap(void) 00085 { 00086 /* Interrupts should be off (and have been off since startup) */ 00087 KASSERT(curthread->t_curspl > 0); 00088 00089 /* Initialize the system LAMEbus data */ 00090 lamebus = lamebus_init(); 00091 00092 /* Probe CPUs (should these be done as device attachments instead?) */ 00093 lamebus_find_cpus(lamebus); 00094 00095 /* 00096 * Print the device name for the main bus. 00097 */ 00098 kprintf("lamebus0 (system main bus)\n"); 00099 00100 /* 00101 * Now we can take interrupts without croaking, so turn them on. 00102 * Some device probes might require being able to get interrupts. 00103 */ 00104 00105 spl0(); 00106 00107 /* 00108 * Now probe all the devices attached to the bus. 00109 * (This amounts to all devices.) 00110 */ 00111 autoconf_lamebus(lamebus, 0); 00112 00113 /* 00114 * Configure the MIPS on-chip timer to interrupt HZ times a second. 00115 */ 00116 mips_timer_set(CPU_FREQUENCY / HZ); 00117 } 00118 00119 /* 00120 * Start all secondary CPUs. 00121 */ 00122 void 00123 mainbus_start_cpus(void) 00124 { 00125 lamebus_start_cpus(lamebus); 00126 } 00127 00128 /* 00129 * Function to generate the memory address (in the uncached segment) 00130 * for the specified offset into the specified slot's region of the 00131 * LAMEbus. 00132 */ 00133 void * 00134 lamebus_map_area(struct lamebus_softc *bus, int slot, uint32_t offset) 00135 { 00136 uint32_t address; 00137 00138 (void)bus; // not needed 00139 00140 KASSERT(slot >= 0 && slot < LB_NSLOTS); 00141 00142 address = LB_BASEADDR + slot*LB_SLOT_SIZE + offset; 00143 return (void *)address; 00144 } 00145 00146 /* 00147 * Read a 32-bit register from a LAMEbus device. 00148 */ 00149 uint32_t 00150 lamebus_read_register(struct lamebus_softc *bus, int slot, uint32_t offset) 00151 { 00152 uint32_t *ptr = lamebus_map_area(bus, slot, offset); 00153 00154 return *ptr; 00155 } 00156 00157 /* 00158 * Write a 32-bit register of a LAMEbus device. 00159 */ 00160 void 00161 lamebus_write_register(struct lamebus_softc *bus, int slot, 00162 uint32_t offset, uint32_t val) 00163 { 00164 uint32_t *ptr = lamebus_map_area(bus, slot, offset); 00165 00166 *ptr = val; 00167 } 00168 00169 00170 /* 00171 * Power off the system. 00172 */ 00173 void 00174 mainbus_poweroff(void) 00175 { 00176 /* 00177 * 00178 * Note that lamebus_write_register() doesn't actually access 00179 * the bus argument, so this will still work if we get here 00180 * before the bus is initialized. 00181 */ 00182 lamebus_poweroff(lamebus); 00183 } 00184 00185 /* 00186 * Reboot the system. 00187 */ 00188 void 00189 mainbus_reboot(void) 00190 { 00191 /* 00192 * The MIPS doesn't appear to have any on-chip reset. 00193 * LAMEbus doesn't have a reset control, so we just 00194 * power off instead of rebooting. This would not be 00195 * so great in a real system, but it's fine for what 00196 * we're doing. 00197 */ 00198 kprintf("Cannot reboot - powering off instead, sorry.\n"); 00199 mainbus_poweroff(); 00200 } 00201 00202 /* 00203 * Halt the system. 00204 * On some systems, this would return to the boot monitor. But we don't 00205 * have one. 00206 */ 00207 void 00208 mainbus_halt(void) 00209 { 00210 cpu_halt(); 00211 } 00212 00213 /* 00214 * Called to reset the system from panic(). 00215 * 00216 * By the time we get here, the system may well be sufficiently hosed 00217 * as to panic recursively if we do much of anything. So just power off. 00218 * (We'd reboot, but System/161 doesn't do that.) 00219 */ 00220 void 00221 mainbus_panic(void) 00222 { 00223 mainbus_poweroff(); 00224 } 00225 00226 /* 00227 * Function to get the size of installed physical RAM from the LAMEbus 00228 * controller. 00229 */ 00230 uint32_t 00231 mainbus_ramsize(void) 00232 { 00233 return lamebus_ramsize(); 00234 } 00235 00236 /* 00237 * Send IPI. 00238 */ 00239 void 00240 mainbus_send_ipi(struct cpu *target) 00241 { 00242 lamebus_assert_ipi(lamebus, target); 00243 } 00244 00245 /* 00246 * Interrupt dispatcher. 00247 */ 00248 00249 /* Wiring of LAMEbus interrupts to bits in the cause register */ 00250 #define LAMEBUS_IRQ_BIT 0x00000400 /* all system bus slots */ 00251 #define LAMEBUS_IPI_BIT 0x00000800 /* inter-processor interrupt */ 00252 #define MIPS_TIMER_BIT 0x00008000 /* on-chip timer */ 00253 00254 void 00255 mainbus_interrupt(struct trapframe *tf) 00256 { 00257 uint32_t cause; 00258 00259 /* interrupts should be off */ 00260 KASSERT(curthread->t_curspl > 0); 00261 00262 cause = tf->tf_cause; 00263 if (cause & LAMEBUS_IRQ_BIT) { 00264 lamebus_interrupt(lamebus); 00265 } 00266 else if (cause & LAMEBUS_IPI_BIT) { 00267 interprocessor_interrupt(); 00268 lamebus_clear_ipi(lamebus, curcpu); 00269 } 00270 else if (cause & MIPS_TIMER_BIT) { 00271 /* Reset the timer (this clears the interrupt) */ 00272 mips_timer_set(CPU_FREQUENCY / HZ); 00273 /* and call hardclock */ 00274 hardclock(); 00275 } 00276 else { 00277 panic("Unknown interrupt; cause register is %08x\n", cause); 00278 } 00279 }