1 /*-
2 * Copyright (c) 2006-2009 RMI Corporation
3 * Copyright (c) 2002-2004 Juli Mallett <jmallett@FreeBSD.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 */
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD: releng/8.2/sys/mips/rmi/xlr_machdep.c 215938 2010-11-27 12:26:40Z jchandra $");
30
31 #include "opt_ddb.h"
32
33 #include <sys/param.h>
34 #include <sys/bus.h>
35 #include <sys/conf.h>
36 #include <sys/rtprio.h>
37 #include <sys/systm.h>
38 #include <sys/interrupt.h>
39 #include <sys/limits.h>
40 #include <sys/lock.h>
41 #include <sys/malloc.h>
42 #include <sys/mutex.h>
43 #include <sys/random.h>
44
45 #include <sys/cons.h> /* cinit() */
46 #include <sys/kdb.h>
47 #include <sys/reboot.h>
48 #include <sys/queue.h>
49 #include <sys/smp.h>
50 #include <sys/timetc.h>
51
52 #include <vm/vm.h>
53 #include <vm/vm_page.h>
54
55 #include <machine/cpu.h>
56 #include <machine/cpufunc.h>
57 #include <machine/cpuinfo.h>
58 #include <machine/cpuregs.h>
59 #include <machine/frame.h>
60 #include <machine/hwfunc.h>
61 #include <machine/md_var.h>
62 #include <machine/asm.h>
63 #include <machine/pmap.h>
64 #include <machine/trap.h>
65 #include <machine/clock.h>
66 #include <machine/fls64.h>
67 #include <machine/intr_machdep.h>
68 #include <machine/smp.h>
69
70 #include <mips/rmi/iomap.h>
71 #include <mips/rmi/msgring.h>
72 #include <mips/rmi/interrupt.h>
73 #include <mips/rmi/pic.h>
74 #include <mips/rmi/board.h>
75 #include <mips/rmi/rmi_mips_exts.h>
76 #include <mips/rmi/rmi_boot_info.h>
77
78 void mpwait(void);
79 unsigned long xlr_io_base = (unsigned long)(DEFAULT_XLR_IO_BASE);
80
81 /* 4KB static data aread to keep a copy of the bootload env until
82 the dynamic kenv is setup */
83 char boot1_env[4096];
84 int rmi_spin_mutex_safe=0;
85 struct mtx xlr_pic_lock;
86
87 /*
88 * Parameters from boot loader
89 */
90 struct boot1_info xlr_boot1_info;
91 int xlr_run_mode;
92 int xlr_argc;
93 int32_t *xlr_argv, *xlr_envp;
94 uint64_t cpu_mask_info;
95 uint32_t xlr_online_cpumask;
96 uint32_t xlr_core_cpu_mask = 0x1; /* Core 0 thread 0 is always there */
97
98 int xlr_shtlb_enabled;
99 int xlr_ncores;
100 int xlr_threads_per_core;
101 uint32_t xlr_hw_thread_mask;
102 int xlr_cpuid_to_hwtid[MAXCPU];
103 int xlr_hwtid_to_cpuid[MAXCPU];
104
105 static void
106 xlr_setup_mmu_split(void)
107 {
108 uint64_t mmu_setup;
109 int val = 0;
110
111 if (xlr_threads_per_core == 4 && xlr_shtlb_enabled == 0)
112 return; /* no change from boot setup */
113
114 switch (xlr_threads_per_core) {
115 case 1:
116 val = 0; break;
117 case 2:
118 val = 2; break;
119 case 4:
120 val = 3; break;
121 }
122
123 mmu_setup = read_xlr_ctrl_register(4, 0);
124 mmu_setup = mmu_setup & ~0x06;
125 mmu_setup |= (val << 1);
126
127 /* turn on global mode */
128 if (xlr_shtlb_enabled)
129 mmu_setup |= 0x01;
130
131 write_xlr_ctrl_register(4, 0, mmu_setup);
132 }
133
134 static void
135 xlr_parse_mmu_options(void)
136 {
137 #ifdef notyet
138 char *hw_env, *start, *end;
139 #endif
140 uint32_t cpu_map;
141 uint8_t core0_thr_mask, core_thr_mask;
142 int i, j, k;
143
144 /* First check for the shared TLB setup */
145 xlr_shtlb_enabled = 0;
146 #ifdef notyet
147 /*
148 * We don't support sharing TLB per core - TODO
149 */
150 xlr_shtlb_enabled = 0;
151 if ((hw_env = getenv("xlr.shtlb")) != NULL) {
152 start = hw_env;
153 tmp = strtoul(start, &end, 0);
154 if (start != end)
155 xlr_shtlb_enabled = (tmp != 0);
156 else
157 printf("Bad value for xlr.shtlb [%s]\n", hw_env);
158 freeenv(hw_env);
159 }
160 #endif
161 /*
162 * XLR supports splitting the 64 TLB entries across one, two or four
163 * threads (split mode). XLR also allows the 64 TLB entries to be shared
164 * across all threads in the core using a global flag (shared TLB mode).
165 * We will support 1/2/4 threads in split mode or shared mode.
166 *
167 */
168 xlr_ncores = 1;
169 cpu_map = xlr_boot1_info.cpu_online_map;
170
171 #ifndef SMP /* Uniprocessor! */
172 if (cpu_map != 0x1) {
173 printf("WARNING: Starting uniprocessor kernel on cpumask [0x%lx]!\n"
174 "WARNING: Other CPUs will be unused.\n", (u_long)cpu_map);
175 cpu_map = 0x1;
176 }
177 #endif
178 core0_thr_mask = cpu_map & 0xf;
179 switch (core0_thr_mask) {
180 case 1:
181 xlr_threads_per_core = 1; break;
182 case 3:
183 xlr_threads_per_core = 2; break;
184 case 0xf:
185 xlr_threads_per_core = 4; break;
186 default:
187 goto unsupp;
188 }
189
190 /* Verify other cores CPU masks */
191 for (i = 1; i < XLR_MAX_CORES; i++) {
192 core_thr_mask = (cpu_map >> (i*4)) & 0xf;
193 if (core_thr_mask) {
194 if (core_thr_mask != core0_thr_mask)
195 goto unsupp;
196 xlr_ncores++;
197 }
198 }
199 xlr_hw_thread_mask = cpu_map;
200
201 /* setup hardware processor id to cpu id mapping */
202 for (i = 0; i< MAXCPU; i++)
203 xlr_cpuid_to_hwtid[i] =
204 xlr_hwtid_to_cpuid [i] = -1;
205 for (i = 0, k = 0; i < XLR_MAX_CORES; i++) {
206 if (((cpu_map >> (i*4)) & 0xf) == 0)
207 continue;
208 for (j = 0; j < xlr_threads_per_core; j++) {
209 xlr_cpuid_to_hwtid[k] = i*4 + j;
210 xlr_hwtid_to_cpuid[i*4 + j] = k;
211 k++;
212 }
213 }
214
215 /* setup for the startup core */
216 xlr_setup_mmu_split();
217 return;
218
219 unsupp:
220 printf("ERROR : Unsupported CPU mask [use 1,2 or 4 threads per core].\n"
221 "\tcore0 thread mask [%lx], boot cpu mask [%lx]\n"
222 "\tUsing default, 16 TLB entries per CPU, split mode\n",
223 (u_long)core0_thr_mask, (u_long)cpu_map);
224 panic("Invalid CPU mask - halting.\n");
225 return;
226 }
227
228 static void
229 xlr_set_boot_flags(void)
230 {
231 char *p;
232
233 p = getenv("bootflags");
234 if (p == NULL)
235 p = getenv("boot_flags"); /* old style */
236 if (p == NULL)
237 return;
238
239 for (; p && *p != '\0'; p++) {
240 switch (*p) {
241 case 'd':
242 case 'D':
243 boothowto |= RB_KDB;
244 break;
245 case 'g':
246 case 'G':
247 boothowto |= RB_GDB;
248 break;
249 case 'v':
250 case 'V':
251 boothowto |= RB_VERBOSE;
252 break;
253
254 case 's': /* single-user (default, supported for sanity) */
255 case 'S':
256 boothowto |= RB_SINGLE;
257 break;
258
259 default:
260 printf("Unrecognized boot flag '%c'.\n", *p);
261 break;
262 }
263 }
264
265 freeenv(p);
266 return;
267 }
268 extern uint32_t _end;
269
270 static void
271 mips_init(void)
272 {
273 init_param1();
274 init_param2(physmem);
275
276 mips_cpu_init();
277 cpuinfo.cache_coherent_dma = TRUE;
278 pmap_bootstrap();
279 #ifdef DDB
280 kdb_init();
281 if (boothowto & RB_KDB) {
282 kdb_enter("Boot flags requested debugger", NULL);
283 }
284 #endif
285 mips_proc0_init();
286 mutex_init();
287 }
288
289 u_int
290 platform_get_timecount(struct timecounter *tc __unused)
291 {
292
293 return (0xffffffffU - pic_timer_count32(PIC_CLOCK_TIMER));
294 }
295
296 static void
297 xlr_pic_init(void)
298 {
299 struct timecounter pic_timecounter = {
300 platform_get_timecount, /* get_timecount */
301 0, /* no poll_pps */
302 ~0U, /* counter_mask */
303 PIC_TIMER_HZ, /* frequency */
304 "XLRPIC", /* name */
305 2000, /* quality (adjusted in code) */
306 };
307 xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET);
308 int i, irq;
309
310 write_c0_eimr64(0ULL);
311 mtx_init(&xlr_pic_lock, "pic", NULL, MTX_SPIN);
312 xlr_write_reg(mmio, PIC_CTRL, 0);
313
314 /* Initialize all IRT entries */
315 for (i = 0; i < PIC_NUM_IRTS; i++) {
316 irq = PIC_INTR_TO_IRQ(i);
317
318 /*
319 * Disable all IRTs. Set defaults (local scheduling, high
320 * polarity, level * triggered, and CPU irq)
321 */
322 xlr_write_reg(mmio, PIC_IRT_1(i), (1 << 30) | (1 << 6) | irq);
323 /* Bind all PIC irqs to cpu 0 */
324 xlr_write_reg(mmio, PIC_IRT_0(i), 0x01);
325 }
326
327 /* Setup timer 7 of PIC as a timestamp, no interrupts */
328 pic_init_timer(PIC_CLOCK_TIMER);
329 pic_set_timer(PIC_CLOCK_TIMER, ~UINT64_C(0));
330 platform_timecounter = &pic_timecounter;
331 }
332
333 static void
334 xlr_mem_init(void)
335 {
336 struct xlr_boot1_mem_map *boot_map;
337 vm_size_t physsz = 0;
338 int i, j;
339
340 /* get physical memory info from boot loader */
341 boot_map = (struct xlr_boot1_mem_map *)
342 (unsigned long)xlr_boot1_info.psb_mem_map;
343 for (i = 0, j = 0; i < boot_map->num_entries; i++, j += 2) {
344 if (boot_map->physmem_map[i].type == BOOT1_MEM_RAM) {
345 if (j == 14) {
346 printf("*** ERROR *** memory map too large ***\n");
347 break;
348 }
349 if (j == 0) {
350 /* TODO FIXME */
351 /* start after kernel end */
352 phys_avail[0] = (vm_paddr_t)
353 MIPS_KSEG0_TO_PHYS(&_end) + 0x20000;
354 /* boot loader start */
355 /* HACK to Use bootloaders memory region */
356 /* TODO FIXME */
357 if (boot_map->physmem_map[0].size == 0x0c000000) {
358 boot_map->physmem_map[0].size = 0x0ff00000;
359 }
360 phys_avail[1] = boot_map->physmem_map[0].addr +
361 boot_map->physmem_map[0].size;
362 printf("First segment: addr:%p -> %p \n",
363 (void *)phys_avail[0],
364 (void *)phys_avail[1]);
365
366 } else {
367 /*
368 * Can't use this code yet, because most of the fixed allocations happen from
369 * the biggest physical area. If we have more than 512M memory the kernel will try
370 * to map from the second are which is not in KSEG0 and not mapped
371 */
372 phys_avail[j] = (vm_paddr_t)
373 boot_map->physmem_map[i].addr;
374 phys_avail[j + 1] = phys_avail[j] +
375 boot_map->physmem_map[i].size;
376 if (phys_avail[j + 1] < phys_avail[j] ) {
377 /* Houston we have an issue. Memory is
378 * larger than possible. Its probably in
379 * 64 bit > 4Gig and we are in 32 bit mode.
380 */
381 phys_avail[j + 1] = 0xfffff000;
382 printf("boot map size was %jx\n",
383 (intmax_t)boot_map->physmem_map[i].size);
384 boot_map->physmem_map[i].size = phys_avail[j + 1]
385 - phys_avail[j];
386 printf("reduced to %jx\n",
387 (intmax_t)boot_map->physmem_map[i].size);
388 }
389 printf("Next segment : addr:%p -> %p \n",
390 (void *)phys_avail[j],
391 (void *)phys_avail[j+1]);
392 }
393 physsz += boot_map->physmem_map[i].size;
394 }
395 }
396
397 /* FIXME XLR TODO */
398 phys_avail[j] = phys_avail[j + 1] = 0;
399 realmem = physmem = btoc(physsz);
400 }
401
402 void
403 platform_start(__register_t a0 __unused,
404 __register_t a1 __unused,
405 __register_t a2 __unused,
406 __register_t a3 __unused)
407 {
408 int i, j;
409 #ifdef SMP
410 uint32_t tmp;
411 void (*wakeup) (void *, void *, unsigned int);
412 #endif
413
414 /* XXX FIXME the code below is not 64 bit clean */
415 /* Save boot loader and other stuff from scratch regs */
416 xlr_boot1_info = *(struct boot1_info *)(intptr_t)(int)read_c0_register32(MIPS_COP_0_OSSCRATCH, 0);
417 cpu_mask_info = read_c0_register64(MIPS_COP_0_OSSCRATCH, 1);
418 xlr_online_cpumask = read_c0_register32(MIPS_COP_0_OSSCRATCH, 2);
419 xlr_run_mode = read_c0_register32(MIPS_COP_0_OSSCRATCH, 3);
420 xlr_argc = read_c0_register32(MIPS_COP_0_OSSCRATCH, 4);
421 /*
422 * argv and envp are passed in array of 32bit pointers
423 */
424 xlr_argv = (int32_t *)(intptr_t)(int)read_c0_register32(MIPS_COP_0_OSSCRATCH, 5);
425 xlr_envp = (int32_t *)(intptr_t)(int)read_c0_register32(MIPS_COP_0_OSSCRATCH, 6);
426
427 /* TODO: Verify the magic number here */
428 /* FIXMELATER: xlr_boot1_info.magic_number */
429
430 /* Initialize pcpu stuff */
431 mips_pcpu0_init();
432
433 /* initialize console so that we have printf */
434 boothowto |= (RB_SERIAL | RB_MULTIPLE); /* Use multiple consoles */
435
436 /* clockrate used by delay, so initialize it here */
437 cpu_clock = xlr_boot1_info.cpu_frequency / 1000000;
438
439 /*
440 * Note the time counter on CPU0 runs not at system clock speed, but
441 * at PIC time counter speed (which is returned by
442 * platform_get_frequency(). Thus we do not use
443 * xlr_boot1_info.cpu_frequency here.
444 */
445 mips_timer_early_init(xlr_boot1_info.cpu_frequency);
446
447 /* Init console please */
448 cninit();
449 printf("Environment (from %d args):\n", xlr_argc - 1);
450 if (xlr_argc == 1)
451 printf("\tNone\n");
452 for (i = 1, j = 0; i < xlr_argc; i++) {
453 char *arg;
454 int len;
455
456 arg = (char *)(intptr_t)xlr_argv[i];
457 len = strlen(arg) + 1; /* include '\0' */
458 if (j + len + 1 > sizeof(boot1_env)) {
459 printf("*** Environment could not be copied in full\n");
460 break;
461 }
462 printf("\t%s\n", arg);
463 memcpy(&boot1_env[j], arg, len);
464 j += len;
465 }
466 boot1_env[j] = '\0';
467 kern_envp = boot1_env;
468
469 xlr_set_boot_flags();
470 xlr_parse_mmu_options();
471
472 xlr_mem_init();
473 /* Set up hz, among others. */
474 mips_init();
475
476 #ifdef SMP
477 /*
478 * If thread 0 of any core is not available then mark whole core as
479 * not available
480 */
481 tmp = xlr_boot1_info.cpu_online_map;
482 for (i = 4; i < MAXCPU; i += 4) {
483 if ((tmp & (0xf << i)) && !(tmp & (0x1 << i))) {
484 /*
485 * Oops.. thread 0 is not available. Disable whole
486 * core
487 */
488 tmp = tmp & ~(0xf << i);
489 printf("WARNING: Core %d is disabled because thread 0"
490 " of this core is not enabled.\n", i / 4);
491 }
492 }
493 xlr_boot1_info.cpu_online_map = tmp;
494
495 /* Wakeup Other cpus, and put them in bsd park code. */
496 wakeup = ((void (*) (void *, void *, unsigned int))
497 (unsigned long)(xlr_boot1_info.wakeup));
498 printf("Waking up CPUs 0x%jx.\n",
499 (intmax_t)xlr_boot1_info.cpu_online_map & ~(0x1U));
500 if (xlr_boot1_info.cpu_online_map & ~(0x1U))
501 wakeup(mpwait, 0,
502 (unsigned int)xlr_boot1_info.cpu_online_map);
503 #endif
504
505 /* xlr specific post initialization */
506 /* initialize other on chip stuff */
507 xlr_board_info_setup();
508 xlr_msgring_config();
509 xlr_pic_init();
510 xlr_msgring_cpu_init();
511
512 mips_timer_init_params(xlr_boot1_info.cpu_frequency, 0);
513
514 printf("Platform specific startup now completes\n");
515 }
516
517 void
518 platform_cpu_init()
519 {
520 }
521
522 void
523 platform_identify(void)
524 {
525
526 printf("Board [%d:%d], processor 0x%08x\n", (int)xlr_boot1_info.board_major_version,
527 (int)xlr_boot1_info.board_minor_version, mips_rd_prid());
528 }
529
530 /*
531 * XXX Maybe return the state of the watchdog in enter, and pass it to
532 * exit? Like spl().
533 */
534 void
535 platform_trap_enter(void)
536 {
537 }
538
539 void
540 platform_reset(void)
541 {
542 xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_GPIO_OFFSET);
543
544 /* write 1 to GPIO software reset register */
545 xlr_write_reg(mmio, 8, 1);
546 }
547
548 void
549 platform_trap_exit(void)
550 {
551 }
552
553 #ifdef SMP
554 int xlr_ap_release[MAXCPU];
555
556 int
557 platform_start_ap(int cpuid)
558 {
559 int hwid = xlr_cpuid_to_hwtid[cpuid];
560
561 if (xlr_boot1_info.cpu_online_map & (1<<hwid)) {
562 /*
563 * other cpus are enabled by the boot loader and they will be
564 * already looping in mpwait, release them
565 */
566 atomic_store_rel_int(&xlr_ap_release[hwid], 1);
567 return (0);
568 } else
569 return (-1);
570 }
571
572 void
573 platform_init_ap(int cpuid)
574 {
575 uint32_t stat;
576
577 /* The first thread has to setup the core MMU split */
578 if (xlr_thr_id() == 0)
579 xlr_setup_mmu_split();
580
581 /* Setup interrupts for secondary CPUs here */
582 stat = mips_rd_status();
583 KASSERT((stat & MIPS_SR_INT_IE) == 0,
584 ("Interrupts enabled in %s!", __func__));
585 stat |= MIPS_SR_COP_2_BIT | MIPS_SR_COP_0_BIT;
586 mips_wr_status(stat);
587
588 write_c0_eimr64(0ULL);
589 xlr_enable_irq(IRQ_IPI);
590 xlr_enable_irq(IRQ_TIMER);
591 if (xlr_thr_id() == 0) {
592 xlr_msgring_cpu_init();
593 xlr_enable_irq(IRQ_MSGRING);
594 }
595
596 return;
597 }
598
599 int
600 platform_ipi_intrnum(void)
601 {
602
603 return (IRQ_IPI);
604 }
605
606 void
607 platform_ipi_send(int cpuid)
608 {
609
610 pic_send_ipi(xlr_cpuid_to_hwtid[cpuid], platform_ipi_intrnum());
611 }
612
613 void
614 platform_ipi_clear(void)
615 {
616 }
617
618 int
619 platform_processor_id(void)
620 {
621
622 return (xlr_hwtid_to_cpuid[xlr_cpu_id()]);
623 }
624
625 int
626 platform_num_processors(void)
627 {
628
629 return (xlr_ncores * xlr_threads_per_core);
630 }
631
632 struct cpu_group *
633 platform_smp_topo()
634 {
635
636 return (smp_topo_2level(CG_SHARE_L2, xlr_ncores, CG_SHARE_L1,
637 xlr_threads_per_core, CG_FLAG_THREAD));
638 }
639 #endif
Cache object: 44c3f5cae6d40b9adfcb112fc67d4326
|