xlr_machdep.c revision 211812
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: head/sys/mips/rmi/xlr_machdep.c 211812 2010-08-25 12:10:20Z 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#include <mips/rmi/rmi_mips_exts.h>
70
71#include <mips/rmi/iomap.h>
72#include <mips/rmi/clock.h>
73#include <mips/rmi/msgring.h>
74#include <mips/rmi/xlrconfig.h>
75#include <mips/rmi/interrupt.h>
76#include <mips/rmi/pic.h>
77#include <mips/rmi/board.h>
78
79void mpwait(void);
80unsigned long xlr_io_base = (unsigned long)(DEFAULT_XLR_IO_BASE);
81
82/* 4KB static data aread to keep a copy of the bootload env until
83   the dynamic kenv is setup */
84char boot1_env[4096];
85int rmi_spin_mutex_safe=0;
86struct mtx xlr_pic_lock;
87
88/*
89 * Parameters from boot loader
90 */
91struct boot1_info xlr_boot1_info;
92int xlr_run_mode;
93int xlr_argc;
94int32_t *xlr_argv, *xlr_envp;
95uint64_t cpu_mask_info;
96uint32_t xlr_online_cpumask;
97uint32_t xlr_core_cpu_mask = 0x1;	/* Core 0 thread 0 is always there */
98
99int xlr_shtlb_enabled;
100int xlr_ncores;
101int xlr_threads_per_core;
102uint32_t xlr_hw_thread_mask;
103int xlr_cpuid_to_hwtid[MAXCPU];
104int xlr_hwtid_to_cpuid[MAXCPU];
105
106static void
107xlr_setup_mmu_split(void)
108{
109	int mmu_setup;
110	int val = 0;
111
112	if (xlr_threads_per_core == 4 && xlr_shtlb_enabled == 0)
113		return;   /* no change from boot setup */
114
115	switch (xlr_threads_per_core) {
116	case 1:
117		val = 0; break;
118	case 2:
119		val = 2; break;
120	case 4:
121		val = 3; break;
122	}
123
124	mmu_setup = read_32bit_phnx_ctrl_reg(4, 0);
125	mmu_setup = mmu_setup & ~0x06;
126	mmu_setup |= (val << 1);
127
128	/* turn on global mode */
129	if (xlr_shtlb_enabled)
130		mmu_setup |= 0x01;
131
132	write_32bit_phnx_ctrl_reg(4, 0, mmu_setup);
133}
134
135static void
136xlr_parse_mmu_options(void)
137{
138#ifdef notyet
139	char *hw_env, *start, *end;
140#endif
141	uint32_t cpu_map;
142	uint8_t core0_thr_mask, core_thr_mask;
143	int i, j, k;
144
145	/* First check for the shared TLB setup */
146	xlr_shtlb_enabled = 0;
147#ifdef notyet
148	/*
149	 * We don't support sharing TLB per core - TODO
150	 */
151	xlr_shtlb_enabled = 0;
152	if ((hw_env = getenv("xlr.shtlb")) != NULL) {
153		start = hw_env;
154		tmp = strtoul(start, &end, 0);
155		if (start != end)
156			xlr_shtlb_enabled = (tmp != 0);
157		else
158			printf("Bad value for xlr.shtlb [%s]\n", hw_env);
159		freeenv(hw_env);
160	}
161#endif
162	/*
163	 * XLR supports splitting the 64 TLB entries across one, two or four
164	 * threads (split mode).  XLR also allows the 64 TLB entries to be shared
165         * across all threads in the core using a global flag (shared TLB mode).
166         * We will support 1/2/4 threads in split mode or shared mode.
167	 *
168	 */
169	xlr_ncores = 1;
170	cpu_map = xlr_boot1_info.cpu_online_map;
171	core0_thr_mask = cpu_map & 0xf;
172	switch (core0_thr_mask) {
173	case 1:
174		xlr_threads_per_core = 1; break;
175	case 3:
176		xlr_threads_per_core = 2; break;
177	case 0xf:
178		xlr_threads_per_core = 4; break;
179	default:
180		goto unsupp;
181	}
182
183	/* Verify other cores CPU masks */
184	for (i = 1; i < XLR_MAX_CORES; i++) {
185		core_thr_mask = (cpu_map >> (i*4)) & 0xf;
186		if (core_thr_mask) {
187			if (core_thr_mask != core0_thr_mask)
188				goto unsupp;
189			xlr_ncores++;
190		}
191	}
192
193	/* setup hardware processor id to cpu id mapping */
194	xlr_hw_thread_mask = xlr_boot1_info.cpu_online_map;
195	for (i = 0; i< MAXCPU; i++)
196		xlr_cpuid_to_hwtid[i] =
197		    xlr_hwtid_to_cpuid [i] = -1;
198	for (i = 0, k = 0; i < XLR_MAX_CORES; i++) {
199		if (((cpu_map >> (i*4)) & 0xf) == 0)
200			continue;
201		for (j = 0; j < xlr_threads_per_core; j++) {
202			xlr_cpuid_to_hwtid[k] = i*4 + j;
203			xlr_hwtid_to_cpuid[i*4 + j] = k;
204			k++;
205		}
206	}
207
208	/* setup for the startup core */
209	xlr_setup_mmu_split();
210	return;
211
212unsupp:
213	printf("ERROR : Unsupported CPU mask [use 1,2 or 4 threads per core].\n"
214	    "\tcore0 thread mask [%lx], boot cpu mask [%lx]\n"
215	    "\tUsing default, 16 TLB entries per CPU, split mode\n",
216	    (u_long)core0_thr_mask, (u_long)cpu_map);
217	panic("Invalid CPU mask - halting.\n");
218	return;
219}
220
221static void
222xlr_set_boot_flags(void)
223{
224	char *p;
225
226	p = getenv("bootflags");
227	if (p == NULL)
228		p = getenv("boot_flags");  /* old style */
229	if (p == NULL)
230		return;
231
232	for (; p && *p != '\0'; p++) {
233		switch (*p) {
234		case 'd':
235		case 'D':
236			boothowto |= RB_KDB;
237			break;
238		case 'g':
239		case 'G':
240			boothowto |= RB_GDB;
241			break;
242		case 'v':
243		case 'V':
244			boothowto |= RB_VERBOSE;
245			break;
246
247		case 's':	/* single-user (default, supported for sanity) */
248		case 'S':
249			boothowto |= RB_SINGLE;
250			break;
251
252		default:
253			printf("Unrecognized boot flag '%c'.\n", *p);
254			break;
255		}
256	}
257
258	freeenv(p);
259	return;
260}
261extern uint32_t _end;
262
263static void
264mips_init(void)
265{
266	init_param1();
267	init_param2(physmem);
268
269	mips_cpu_init();
270	pmap_bootstrap();
271#ifdef DDB
272	kdb_init();
273	if (boothowto & RB_KDB) {
274		kdb_enter("Boot flags requested debugger", NULL);
275	}
276#endif
277	mips_proc0_init();
278	mutex_init();
279}
280
281static void
282xlr_pic_init(void)
283{
284	xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET);
285	int i, level, irq;
286
287	mtx_init(&xlr_pic_lock, "pic", NULL, MTX_SPIN);
288	xlr_write_reg(mmio, PIC_CTRL, 0);
289	for (i = 0; i < PIC_NUM_IRTS; i++) {
290		irq = PIC_INTR_TO_IRQ(i);
291		level = PIC_IRQ_IS_EDGE_TRIGGERED(irq);
292
293		/* Bind all PIC irqs to cpu 0 */
294		xlr_write_reg(mmio, PIC_IRT_0(i), 0x01);
295
296		/*
297		 * Use local scheduling and high polarity for all IRTs
298		 * Invalidate all IRTs, by default
299		 */
300		xlr_write_reg(mmio, PIC_IRT_1(i), (level << 30) | (1 << 6) |
301		    irq);
302	}
303}
304
305static void
306xlr_mem_init(void)
307{
308	struct xlr_boot1_mem_map *boot_map;
309	vm_size_t physsz = 0;
310	int i, j;
311
312	/* get physical memory info from boot loader */
313	boot_map = (struct xlr_boot1_mem_map *)
314	    (unsigned long)xlr_boot1_info.psb_mem_map;
315	for (i = 0, j = 0; i < boot_map->num_entries; i++, j += 2) {
316		if (boot_map->physmem_map[i].type == BOOT1_MEM_RAM) {
317			if (j == 14) {
318				printf("*** ERROR *** memory map too large ***\n");
319				break;
320			}
321			if (j == 0) {
322				/* TODO FIXME  */
323				/* start after kernel end */
324				phys_avail[0] = (vm_paddr_t)
325				    MIPS_KSEG0_TO_PHYS(&_end) + 0x20000;
326				/* boot loader start */
327				/* HACK to Use bootloaders memory region */
328				/* TODO FIXME  */
329				if (boot_map->physmem_map[0].size == 0x0c000000) {
330					boot_map->physmem_map[0].size = 0x0ff00000;
331				}
332				phys_avail[1] = boot_map->physmem_map[0].addr +
333				    boot_map->physmem_map[0].size;
334				printf("First segment: addr:%p -> %p \n",
335				       (void *)phys_avail[0],
336				       (void *)phys_avail[1]);
337
338			} else {
339/*
340 * Can't use this code yet, because most of the fixed allocations happen from
341 * the biggest physical area. If we have more than 512M memory the kernel will try
342 * to map from the second are which is not in KSEG0 and not mapped
343 */
344				phys_avail[j] = (vm_paddr_t)
345				    boot_map->physmem_map[i].addr;
346				phys_avail[j + 1] = phys_avail[j] +
347				    boot_map->physmem_map[i].size;
348				if (phys_avail[j + 1] < phys_avail[j] ) {
349					/* Houston we have an issue. Memory is
350					 * larger than possible. Its probably in
351					 * 64 bit > 4Gig and we are in 32 bit mode.
352					 */
353					phys_avail[j + 1] = 0xfffff000;
354					printf("boot map size was %jx\n",
355					    (intmax_t)boot_map->physmem_map[i].size);
356					boot_map->physmem_map[i].size = phys_avail[j + 1]
357					    - phys_avail[j];
358					printf("reduced to %jx\n",
359					    (intmax_t)boot_map->physmem_map[i].size);
360				}
361				printf("Next segment : addr:%p -> %p \n",
362				       (void *)phys_avail[j],
363				       (void *)phys_avail[j+1]);
364			}
365			physsz += boot_map->physmem_map[i].size;
366		}
367	}
368
369	/* FIXME XLR TODO */
370	phys_avail[j] = phys_avail[j + 1] = 0;
371	realmem = physmem = btoc(physsz);
372}
373
374void
375platform_start(__register_t a0 __unused,
376    __register_t a1 __unused,
377    __register_t a2 __unused,
378    __register_t a3 __unused)
379{
380	int i;
381#ifdef SMP
382	uint32_t tmp;
383	void (*wakeup) (void *, void *, unsigned int);
384#endif
385
386	/* XXX FIXME the code below is not 64 bit clean */
387	/* Save boot loader and other stuff from scratch regs */
388	xlr_boot1_info = *(struct boot1_info *)(intptr_t)(int)read_c0_register32(MIPS_COP_0_OSSCRATCH, 0);
389	cpu_mask_info = read_c0_register64(MIPS_COP_0_OSSCRATCH, 1);
390	xlr_online_cpumask = read_c0_register32(MIPS_COP_0_OSSCRATCH, 2);
391	xlr_run_mode = read_c0_register32(MIPS_COP_0_OSSCRATCH, 3);
392	xlr_argc = read_c0_register32(MIPS_COP_0_OSSCRATCH, 4);
393	/*
394	 * argv and envp are passed in array of 32bit pointers
395	 */
396	xlr_argv = (int32_t *)(intptr_t)(int)read_c0_register32(MIPS_COP_0_OSSCRATCH, 5);
397	xlr_envp = (int32_t *)(intptr_t)(int)read_c0_register32(MIPS_COP_0_OSSCRATCH, 6);
398
399	/* TODO: Verify the magic number here */
400	/* FIXMELATER: xlr_boot1_info.magic_number */
401
402	/* Initialize pcpu stuff */
403	mips_pcpu0_init();
404
405	/* initialize console so that we have printf */
406	boothowto |= (RB_SERIAL | RB_MULTIPLE);	/* Use multiple consoles */
407
408	/* clockrate used by delay, so initialize it here */
409	cpu_clock = xlr_boot1_info.cpu_frequency / 1000000;
410
411	/*
412	 * Note the time counter on CPU0 runs not at system clock speed, but
413	 * at PIC time counter speed (which is returned by
414	 * platform_get_frequency(). Thus we do not use
415	 * xlr_boot1_info.cpu_frequency here.
416	 */
417	mips_timer_early_init(xlr_boot1_info.cpu_frequency);
418
419	/* Init console please */
420	cninit();
421	init_static_kenv(boot1_env, sizeof(boot1_env));
422	printf("Environment (from %d args):\n", xlr_argc - 1);
423	if (xlr_argc == 1)
424		printf("\tNone\n");
425	for (i = 1; i < xlr_argc; i++) {
426		char *n, *arg;
427
428		arg = (char *)(intptr_t)xlr_argv[i];
429		printf("\t%s\n", arg);
430		n = strsep(&arg, "=");
431		if (arg == NULL)
432			setenv(n, "1");
433		else
434			setenv(n, arg);
435	}
436
437	xlr_set_boot_flags();
438	xlr_parse_mmu_options();
439
440	xlr_mem_init();
441	/* Set up hz, among others. */
442	mips_init();
443
444#ifdef SMP
445	/*
446	 * If thread 0 of any core is not available then mark whole core as
447	 * not available
448	 */
449	tmp = xlr_boot1_info.cpu_online_map;
450	for (i = 4; i < MAXCPU; i += 4) {
451		if ((tmp & (0xf << i)) && !(tmp & (0x1 << i))) {
452			/*
453			 * Oops.. thread 0 is not available. Disable whole
454			 * core
455			 */
456			tmp = tmp & ~(0xf << i);
457			printf("WARNING: Core %d is disabled because thread 0"
458			    " of this core is not enabled.\n", i / 4);
459		}
460	}
461	xlr_boot1_info.cpu_online_map = tmp;
462
463	/* Wakeup Other cpus, and put them in bsd park code. */
464	wakeup = ((void (*) (void *, void *, unsigned int))
465	    (unsigned long)(xlr_boot1_info.wakeup));
466	printf("Waking up CPUs 0x%jx.\n",
467	    (intmax_t)xlr_boot1_info.cpu_online_map & ~(0x1U));
468	if (xlr_boot1_info.cpu_online_map & ~(0x1U))
469		wakeup(mpwait, 0,
470		    (unsigned int)xlr_boot1_info.cpu_online_map);
471#endif
472
473	/* xlr specific post initialization */
474	/* initialize other on chip stuff */
475	xlr_board_info_setup();
476	xlr_msgring_config();
477	xlr_pic_init();
478	xlr_msgring_cpu_init();
479
480	mips_timer_init_params(xlr_boot1_info.cpu_frequency, 0);
481
482	printf("Platform specific startup now completes\n");
483}
484
485void
486platform_cpu_init()
487{
488}
489
490void
491platform_identify(void)
492{
493
494	printf("Board [%d:%d], processor 0x%08x\n", (int)xlr_boot1_info.board_major_version,
495	    (int)xlr_boot1_info.board_minor_version, mips_rd_prid());
496}
497
498/*
499 * XXX Maybe return the state of the watchdog in enter, and pass it to
500 * exit?  Like spl().
501 */
502void
503platform_trap_enter(void)
504{
505}
506
507void
508platform_reset(void)
509{
510	xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_GPIO_OFFSET);
511
512	/* write 1 to GPIO software reset register */
513	xlr_write_reg(mmio, 8, 1);
514}
515
516void
517platform_trap_exit(void)
518{
519}
520
521#ifdef SMP
522int xlr_ap_release[MAXCPU];
523
524int
525platform_start_ap(int cpuid)
526{
527	int hwid = xlr_cpuid_to_hwtid[cpuid];
528
529	if (xlr_boot1_info.cpu_online_map & (1<<hwid)) {
530		/*
531		 * other cpus are enabled by the boot loader and they will be
532		 * already looping in mpwait, release them
533		 */
534		atomic_store_rel_int(&xlr_ap_release[hwid], 1);
535		return (0);
536	} else
537		return (-1);
538}
539
540void
541platform_init_ap(int cpuid)
542{
543	uint32_t stat;
544
545	/* The first thread has to setup the core MMU split  */
546	if (xlr_thr_id() == 0)
547		xlr_setup_mmu_split();
548
549	/* Setup interrupts for secondary CPUs here */
550	stat = mips_rd_status();
551	KASSERT((stat & MIPS_SR_INT_IE) == 0,
552	    ("Interrupts enabled in %s!", __func__));
553	stat |= MIPS_SR_COP_2_BIT | MIPS_SR_COP_0_BIT;
554	mips_wr_status(stat);
555
556	xlr_unmask_hard_irq((void *)IRQ_IPI);
557	xlr_unmask_hard_irq((void *)IRQ_TIMER);
558	if (xlr_thr_id() == 0) {
559		xlr_msgring_cpu_init();
560	 	xlr_unmask_hard_irq((void *)IRQ_MSGRING);
561	}
562
563	return;
564}
565
566int
567platform_ipi_intrnum(void)
568{
569
570	return (IRQ_IPI);
571}
572
573void
574platform_ipi_send(int cpuid)
575{
576
577	pic_send_ipi(xlr_cpuid_to_hwtid[cpuid], platform_ipi_intrnum());
578
579}
580
581void
582platform_ipi_clear(void)
583{
584}
585
586int
587platform_processor_id(void)
588{
589
590	return (xlr_hwtid_to_cpuid[xlr_cpu_id()]);
591}
592
593int
594platform_num_processors(void)
595{
596
597	return (xlr_ncores * xlr_threads_per_core);
598}
599
600struct cpu_group *
601platform_smp_topo()
602{
603
604	return (smp_topo_2level(CG_SHARE_L2, xlr_ncores, CG_SHARE_L1,
605		xlr_threads_per_core, CG_FLAG_THREAD));
606}
607#endif
608