1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2007 Bruce M. Simpson. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> 30__FBSDID("$FreeBSD$"); 31 32#include "opt_ddb.h" 33#include "opt_kdb.h" 34 35#include <sys/param.h> 36#include <sys/conf.h> 37#include <sys/kernel.h> 38#include <sys/systm.h> 39#include <sys/imgact.h> 40#include <sys/bio.h> 41#include <sys/buf.h> 42#include <sys/bus.h> 43#include <sys/cpu.h> 44#include <sys/cons.h> 45#include <sys/exec.h> 46#include <sys/ucontext.h> 47#include <sys/proc.h> 48#include <sys/kdb.h> 49#include <sys/ptrace.h> 50#include <sys/reboot.h> 51#include <sys/signalvar.h> 52#include <sys/sysent.h> 53#include <sys/sysproto.h> 54#include <sys/user.h> 55#include <sys/timetc.h> 56 57#include <vm/vm.h> 58#include <vm/vm_object.h> 59#include <vm/vm_page.h> 60 61#include <machine/cache.h> 62#include <machine/clock.h> 63#include <machine/cpu.h> 64#include <machine/cpuinfo.h> 65#include <machine/cpufunc.h> 66#include <machine/cpuregs.h> 67#include <machine/hwfunc.h> 68#include <machine/intr_machdep.h> 69#include <machine/locore.h> 70#include <machine/md_var.h> 71#include <machine/pte.h> 72#include <machine/sigframe.h> 73#include <machine/trap.h> 74#include <machine/vmparam.h> 75 76#ifdef SMP 77#include <sys/smp.h> 78#include <machine/smp.h> 79#endif 80 81#ifdef CFE 82#include <dev/cfe/cfe_api.h> 83#endif 84 85#include "sb_scd.h" 86 87#ifdef DDB 88#ifndef KDB 89#error KDB must be enabled in order for DDB to work! 90#endif 91#endif 92 93#ifdef CFE_ENV 94extern void cfe_env_init(void); 95#endif 96 97extern int *edata; 98extern int *end; 99 100extern char MipsTLBMiss[], MipsTLBMissEnd[]; 101 102void 103platform_cpu_init() 104{ 105 /* Nothing special */ 106} 107 108static void 109sb_intr_init(int cpuid) 110{ 111 int intrnum, intsrc; 112 113 /* 114 * Disable all sources to the interrupt mapper and setup the mapping 115 * between an interrupt source and the mips hard interrupt number. 116 */ 117 for (intsrc = 0; intsrc < NUM_INTSRC; ++intsrc) { 118 intrnum = sb_route_intsrc(intsrc); 119 sb_disable_intsrc(cpuid, intsrc); 120 sb_write_intmap(cpuid, intsrc, intrnum); 121#ifdef SMP 122 /* 123 * Set up the mailbox interrupt mapping. 124 * 125 * The mailbox interrupt is "special" in that it is not shared 126 * with any other interrupt source. 127 */ 128 if (intsrc == INTSRC_MAILBOX3) { 129 intrnum = platform_ipi_hardintr_num(); 130 sb_write_intmap(cpuid, INTSRC_MAILBOX3, intrnum); 131 sb_enable_intsrc(cpuid, INTSRC_MAILBOX3); 132 } 133#endif 134 } 135} 136 137static void 138mips_init(void) 139{ 140 int i, j, cfe_mem_idx, tmp; 141 uint64_t maxmem; 142 143#ifdef CFE_ENV 144 cfe_env_init(); 145#endif 146 147 TUNABLE_INT_FETCH("boothowto", &boothowto); 148 149 if (boothowto & RB_VERBOSE) 150 bootverbose++; 151 152#ifdef MAXMEM 153 tmp = MAXMEM; 154#else 155 tmp = 0; 156#endif 157 TUNABLE_INT_FETCH("hw.physmem", &tmp); 158 maxmem = (uint64_t)tmp * 1024; 159 160 /* 161 * XXX 162 * If we used vm_paddr_t consistently in pmap, etc., we could 163 * use 64-bit page numbers on !n64 systems, too, like i386 164 * does with PAE. 165 */ 166#if !defined(__mips_n64) 167 if (maxmem == 0 || maxmem > 0xffffffff) 168 maxmem = 0xffffffff; 169#endif 170 171#ifdef CFE 172 /* 173 * Query DRAM memory map from CFE. 174 */ 175 physmem = 0; 176 cfe_mem_idx = 0; 177 for (i = 0; i < 10; i += 2) { 178 int result; 179 uint64_t addr, len, type; 180 181 result = cfe_enummem(cfe_mem_idx++, 0, &addr, &len, &type); 182 if (result < 0) { 183 phys_avail[i] = phys_avail[i + 1] = 0; 184 break; 185 } 186 187 KASSERT(type == CFE_MI_AVAILABLE, 188 ("CFE DRAM region is not available?")); 189 190 if (bootverbose) 191 printf("cfe_enummem: 0x%016jx/%ju.\n", addr, len); 192 193 if (maxmem != 0) { 194 if (addr >= maxmem) { 195 printf("Ignoring %ju bytes of memory at 0x%jx " 196 "that is above maxmem %dMB\n", 197 len, addr, 198 (int)(maxmem / (1024 * 1024))); 199 continue; 200 } 201 202 if (addr + len > maxmem) { 203 printf("Ignoring %ju bytes of memory " 204 "that is above maxmem %dMB\n", 205 (addr + len) - maxmem, 206 (int)(maxmem / (1024 * 1024))); 207 len = maxmem - addr; 208 } 209 } 210 211 phys_avail[i] = addr; 212 if (i == 0 && addr == 0) { 213 /* 214 * If this is the first physical memory segment probed 215 * from CFE, omit the region at the start of physical 216 * memory where the kernel has been loaded. 217 */ 218 phys_avail[i] += MIPS_KSEG0_TO_PHYS(kernel_kseg0_end); 219 } 220 phys_avail[i + 1] = addr + len; 221 physmem += len; 222 } 223 224 realmem = btoc(physmem); 225#endif 226 227 for (j = 0; j < i; j++) 228 dump_avail[j] = phys_avail[j]; 229 230 physmem = realmem; 231 232 init_param1(); 233 init_param2(physmem); 234 mips_cpu_init(); 235 236 /* 237 * Sibyte has a L1 data cache coherent with DMA. This includes 238 * on-chip network interfaces as well as PCI/HyperTransport bus 239 * masters. 240 */ 241 cpuinfo.cache_coherent_dma = TRUE; 242 243 /* 244 * XXX 245 * The kernel is running in 32-bit mode but the CFE is running in 246 * 64-bit mode. So the SR_KX bit in the status register is turned 247 * on by the CFE every time we call into it - for e.g. CFE_CONSOLE. 248 * 249 * This means that if get a TLB miss for any address above 0xc0000000 250 * and the SR_KX bit is set then we will end up in the XTLB exception 251 * vector. 252 * 253 * For now work around this by copying the TLB exception handling 254 * code to the XTLB exception vector. 255 */ 256 { 257 bcopy(MipsTLBMiss, (void *)MIPS_XTLB_MISS_EXC_VEC, 258 MipsTLBMissEnd - MipsTLBMiss); 259 260 mips_icache_sync_all(); 261 mips_dcache_wbinv_all(); 262 } 263 264 pmap_bootstrap(); 265 mips_proc0_init(); 266 mutex_init(); 267 268 kdb_init(); 269#ifdef KDB 270 if (boothowto & RB_KDB) 271 kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); 272#endif 273} 274 275void 276platform_reset(void) 277{ 278 279 /* 280 * XXX SMP 281 * XXX flush data caches 282 */ 283 sb_system_reset(); 284} 285 286static void 287kseg0_map_coherent(void) 288{ 289 uint32_t config; 290 const int CFG_K0_COHERENT = 5; 291 292 config = mips_rd_config(); 293 config &= ~MIPS_CONFIG_K0_MASK; 294 config |= CFG_K0_COHERENT; 295 mips_wr_config(config); 296} 297 298#ifdef SMP 299void 300platform_ipi_send(int cpuid) 301{ 302 KASSERT(cpuid == 0 || cpuid == 1, 303 ("platform_ipi_send: invalid cpuid %d", cpuid)); 304 305 sb_set_mailbox(cpuid, 1ULL); 306} 307 308void 309platform_ipi_clear(void) 310{ 311 int cpuid; 312 313 cpuid = PCPU_GET(cpuid); 314 sb_clear_mailbox(cpuid, 1ULL); 315} 316 317int 318platform_ipi_hardintr_num(void) 319{ 320 321 return (4); 322} 323 324int 325platform_ipi_softintr_num(void) 326{ 327 328 return (-1); 329} 330 331struct cpu_group * 332platform_smp_topo(void) 333{ 334 335 return (smp_topo_none()); 336} 337 338void 339platform_init_ap(int cpuid) 340{ 341 int ipi_int_mask, clock_int_mask; 342 343 KASSERT(cpuid == 1, ("AP has an invalid cpu id %d", cpuid)); 344 345 /* 346 * Make sure that kseg0 is mapped cacheable-coherent 347 */ 348 kseg0_map_coherent(); 349 350 sb_intr_init(cpuid); 351 352 /* 353 * Unmask the clock and ipi interrupts. 354 */ 355 clock_int_mask = hard_int_mask(5); 356 ipi_int_mask = hard_int_mask(platform_ipi_hardintr_num()); 357 set_intr_mask(ipi_int_mask | clock_int_mask); 358} 359 360int 361platform_start_ap(int cpuid) 362{ 363#ifdef CFE 364 int error; 365 366 if ((error = cfe_cpu_start(cpuid, mpentry, 0, 0, 0))) { 367 printf("cfe_cpu_start error: %d\n", error); 368 return (-1); 369 } else { 370 return (0); 371 } 372#else 373 return (-1); 374#endif /* CFE */ 375} 376#endif /* SMP */ 377 378static u_int 379sb_get_timecount(struct timecounter *tc) 380{ 381 382 return ((u_int)sb_zbbus_cycle_count()); 383} 384 385static void 386sb_timecounter_init(void) 387{ 388 static struct timecounter sb_timecounter = { 389 sb_get_timecount, 390 NULL, 391 ~0u, 392 0, 393 "sibyte_zbbus_counter", 394 2000 395 }; 396 397 /* 398 * The ZBbus cycle counter runs at half the cpu frequency. 399 */ 400 sb_timecounter.tc_frequency = sb_cpu_speed() / 2; 401 platform_timecounter = &sb_timecounter; 402} 403 404void 405platform_start(__register_t a0, __register_t a1, __register_t a2, 406 __register_t a3) 407{ 408 /* 409 * Make sure that kseg0 is mapped cacheable-coherent 410 */ 411 kseg0_map_coherent(); 412 413 /* clear the BSS and SBSS segments */ 414 memset(&edata, 0, (vm_offset_t)&end - (vm_offset_t)&edata); 415 mips_postboot_fixup(); 416 417 sb_intr_init(0); 418 sb_timecounter_init(); 419 420 /* Initialize pcpu stuff */ 421 mips_pcpu0_init(); 422 423#ifdef CFE 424 /* 425 * Initialize CFE firmware trampolines before 426 * we initialize the low-level console. 427 * 428 * CFE passes the following values in registers: 429 * a0: firmware handle 430 * a2: firmware entry point 431 * a3: entry point seal 432 */ 433 if (a3 == CFE_EPTSEAL) 434 cfe_init(a0, a2); 435#endif 436 cninit(); 437 438 mips_init(); 439 440 mips_timer_init_params(sb_cpu_speed(), 0); 441} 442