xref: /openbsd/sys/arch/octeon/octeon/machdep.c (revision bb00e811)
1*bb00e811Sclaudio /*	$OpenBSD: machdep.c,v 1.137 2023/10/24 13:20:10 claudio Exp $ */
2c6b2ceb4Ssyuu 
3c6b2ceb4Ssyuu /*
4c6b2ceb4Ssyuu  * Copyright (c) 2009, 2010 Miodrag Vallat.
53a62b615Svisa  * Copyright (c) 2019 Visa Hankala.
6c6b2ceb4Ssyuu  *
7c6b2ceb4Ssyuu  * Permission to use, copy, modify, and distribute this software for any
8c6b2ceb4Ssyuu  * purpose with or without fee is hereby granted, provided that the above
9c6b2ceb4Ssyuu  * copyright notice and this permission notice appear in all copies.
10c6b2ceb4Ssyuu  *
11c6b2ceb4Ssyuu  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12c6b2ceb4Ssyuu  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13c6b2ceb4Ssyuu  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14c6b2ceb4Ssyuu  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15c6b2ceb4Ssyuu  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16c6b2ceb4Ssyuu  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17c6b2ceb4Ssyuu  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18c6b2ceb4Ssyuu  */
19c6b2ceb4Ssyuu /*
20c6b2ceb4Ssyuu  * Copyright (c) 2003-2004 Opsycon AB  (www.opsycon.se / www.opsycon.com)
21c6b2ceb4Ssyuu  *
22c6b2ceb4Ssyuu  * Redistribution and use in source and binary forms, with or without
23c6b2ceb4Ssyuu  * modification, are permitted provided that the following conditions
24c6b2ceb4Ssyuu  * are met:
25c6b2ceb4Ssyuu  * 1. Redistributions of source code must retain the above copyright
26c6b2ceb4Ssyuu  *    notice, this list of conditions and the following disclaimer.
27c6b2ceb4Ssyuu  * 2. Redistributions in binary form must reproduce the above copyright
28c6b2ceb4Ssyuu  *    notice, this list of conditions and the following disclaimer in the
29c6b2ceb4Ssyuu  *    documentation and/or other materials provided with the distribution.
30c6b2ceb4Ssyuu  *
31c6b2ceb4Ssyuu  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
32c6b2ceb4Ssyuu  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
33c6b2ceb4Ssyuu  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34c6b2ceb4Ssyuu  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
35c6b2ceb4Ssyuu  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36c6b2ceb4Ssyuu  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37c6b2ceb4Ssyuu  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38c6b2ceb4Ssyuu  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
39c6b2ceb4Ssyuu  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
40c6b2ceb4Ssyuu  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41c6b2ceb4Ssyuu  * SUCH DAMAGE.
42c6b2ceb4Ssyuu  *
43c6b2ceb4Ssyuu  */
44c6b2ceb4Ssyuu #include <sys/param.h>
45c6b2ceb4Ssyuu #include <sys/systm.h>
46c6b2ceb4Ssyuu #include <sys/kernel.h>
47c6b2ceb4Ssyuu #include <sys/proc.h>
48c6b2ceb4Ssyuu #include <sys/buf.h>
49c6b2ceb4Ssyuu #include <sys/reboot.h>
50c6b2ceb4Ssyuu #include <sys/conf.h>
51c6b2ceb4Ssyuu #include <sys/msgbuf.h>
52c6b2ceb4Ssyuu #include <sys/tty.h>
53c6b2ceb4Ssyuu #include <sys/user.h>
54c6b2ceb4Ssyuu #include <sys/exec.h>
55c6b2ceb4Ssyuu #include <sys/sysctl.h>
56c6b2ceb4Ssyuu #include <sys/mount.h>
57c6b2ceb4Ssyuu #include <sys/syscallargs.h>
58c6b2ceb4Ssyuu #include <sys/exec_elf.h>
59acef65c9Svisa #include <sys/timetc.h>
60c6b2ceb4Ssyuu #ifdef SYSVSHM
61c6b2ceb4Ssyuu #include <sys/shm.h>
62c6b2ceb4Ssyuu #endif
63c6b2ceb4Ssyuu #ifdef SYSVSEM
64c6b2ceb4Ssyuu #include <sys/sem.h>
65c6b2ceb4Ssyuu #endif
66c6b2ceb4Ssyuu 
677d9ca166Sderaadt #include <net/if.h>
68a43a5a68Smpi 
69c6b2ceb4Ssyuu #include <uvm/uvm_extern.h>
70c6b2ceb4Ssyuu 
71c6b2ceb4Ssyuu #include <machine/db_machdep.h>
72c6b2ceb4Ssyuu #include <ddb/db_interface.h>
73c6b2ceb4Ssyuu 
74c6b2ceb4Ssyuu #include <machine/autoconf.h>
75737df64eSmiod #include <mips64/cache.h>
76c6b2ceb4Ssyuu #include <machine/cpu.h>
777b6ae6a5Smiod #include <mips64/mips_cpu.h>
78c6b2ceb4Ssyuu #include <machine/memconf.h>
79c6b2ceb4Ssyuu 
80c6b2ceb4Ssyuu #include <dev/cons.h>
818a4f0236Svisa #include <dev/ofw/fdt.h>
82c6b2ceb4Ssyuu 
83f4fee9beSvisa #include <octeon/dev/cn30xxcorereg.h>
84acef65c9Svisa #include <octeon/dev/cn30xxipdreg.h>
8561e15267Ssyuu #include <octeon/dev/iobusvar.h>
86a81120d9Sjasper #include <machine/octeonreg.h>
877b0d27bbSjasper #include <machine/octeonvar.h>
885f139a3aSjmatthew #include <machine/octeon_model.h>
89b9a81422Ssyuu 
903a62b615Svisa #include "octboot.h"
913a62b615Svisa 
92c6b2ceb4Ssyuu /* The following is used externally (sysctl_hw) */
93c6b2ceb4Ssyuu char	machine[] = MACHINE;		/* Machine "architecture" */
94534dab3bSjasper char	cpu_model[64];
95c6b2ceb4Ssyuu 
96c6b2ceb4Ssyuu struct uvm_constraint_range  dma_constraint = { 0x0, 0xffffffffUL };
97c6b2ceb4Ssyuu struct uvm_constraint_range *uvm_md_constraints[] = { NULL };
98c6b2ceb4Ssyuu 
99c6b2ceb4Ssyuu vm_map_t exec_map;
100c6b2ceb4Ssyuu vm_map_t phys_map;
101c6b2ceb4Ssyuu 
1029e8849fbSvisa extern struct timecounter cp0_timecounter;
1036ce0dd2eSvisa extern uint8_t dt_blob_start[];
1046ce0dd2eSvisa 
1052bbf581cSvisa enum octeon_board octeon_board;
1065a60bedeSjasper struct boot_desc *octeon_boot_desc;
1075a60bedeSjasper struct boot_info *octeon_boot_info;
1085a60bedeSjasper 
1098a4f0236Svisa void		*octeon_fdt;
110358aeffeSvisa unsigned int	 octeon_ver;
1118a4f0236Svisa 
112c6b2ceb4Ssyuu /*
113c6b2ceb4Ssyuu  * safepri is a safe priority for sleep to set for a spin-wait
114c6b2ceb4Ssyuu  * during autoconfiguration or after a panic.
115c6b2ceb4Ssyuu  */
116c6b2ceb4Ssyuu int   safepri = 0;
117c6b2ceb4Ssyuu 
118c6b2ceb4Ssyuu caddr_t	msgbufbase;
119c6b2ceb4Ssyuu 
120c6b2ceb4Ssyuu int	physmem;		/* Max supported memory, changes to actual. */
121c6b2ceb4Ssyuu int	ncpu = 1;		/* At least one CPU in the system. */
122c6b2ceb4Ssyuu struct	user *proc0paddr;
123c6b2ceb4Ssyuu 
124c6b2ceb4Ssyuu struct cpu_hwinfo bootcpu_hwinfo;
125c6b2ceb4Ssyuu 
126c6b2ceb4Ssyuu /* Pointers to the start and end of the symbol table. */
127c6b2ceb4Ssyuu caddr_t	ssym;
128c6b2ceb4Ssyuu caddr_t	esym;
129c6b2ceb4Ssyuu caddr_t	ekern;
130c6b2ceb4Ssyuu 
131c6b2ceb4Ssyuu struct phys_mem_desc mem_layout[MAXMEMSEGS];
132c6b2ceb4Ssyuu 
133c6b2ceb4Ssyuu void		dumpsys(void);
134c6b2ceb4Ssyuu void		dumpconf(void);
1358e9ccc25Svisa vaddr_t		mips_init(register_t, register_t, register_t, register_t);
13694483548Svisa int		is_memory_range(paddr_t, psize_t, psize_t);
137b9a81422Ssyuu void		octeon_memory_init(struct boot_info *);
1389e8849fbSvisa void		octeon_sync_tc(vaddr_t, uint64_t, uint64_t);
139d09664daSjasper int		octeon_cpuspeed(int *);
1408f99340cSvisa void		octeon_tlb_init(void);
14101f63e54Sjasper static void	process_bootargs(void);
142b5503b64Sjasper static uint64_t	get_ncpusfound(void);
1432bbf581cSvisa static enum octeon_board get_octeon_board(void);
14401f63e54Sjasper 
145874cea07Sderaadt cons_decl(octuart);
146874cea07Sderaadt struct consdev uartcons = cons_init(octuart);
147fa1c4bcdSsyuu 
14839db07acSvisa u_int		ioclock_get_timecount(struct timecounter *);
149acef65c9Svisa 
15039db07acSvisa struct timecounter ioclock_timecounter = {
15139db07acSvisa 	.tc_get_timecount = ioclock_get_timecount,
152acef65c9Svisa 	.tc_counter_mask = 0xffffffff,	/* truncated to 32 bits */
153acef65c9Svisa 	.tc_frequency = 0,		/* determined at runtime */
15439db07acSvisa 	.tc_name = "ioclock",
15539db07acSvisa 	.tc_quality = 0,		/* ioclock can be overridden
156acef65c9Svisa 					 * by cp0 counter */
157d82e6535Spirofti 	.tc_priv = 0,			/* clock register,
15839db07acSvisa 					 * determined at runtime */
159d82e6535Spirofti 	.tc_user = 0,			/* expose to user */
160acef65c9Svisa };
161acef65c9Svisa 
162a084a2f8Svisa static int
atoi(const char * s)163a084a2f8Svisa atoi(const char *s)
164a084a2f8Svisa {
165a084a2f8Svisa 	int n, neg;
166a084a2f8Svisa 
167a084a2f8Svisa 	n = 0;
168a084a2f8Svisa 	neg = 0;
169a084a2f8Svisa 
170a084a2f8Svisa 	while (*s == '-') {
171a084a2f8Svisa 		s++;
172a084a2f8Svisa 		neg = !neg;
173a084a2f8Svisa 	}
174a084a2f8Svisa 
175a084a2f8Svisa 	while (*s != '\0') {
176a084a2f8Svisa 		if (*s < '0' || *s > '9')
177a084a2f8Svisa 			break;
178a084a2f8Svisa 
179a084a2f8Svisa 		n = (10 * n) + (*s - '0');
180a084a2f8Svisa 		s++;
181a084a2f8Svisa 	}
182a084a2f8Svisa 
183a084a2f8Svisa 	return (neg ? -n : n);
184a084a2f8Svisa }
185a084a2f8Svisa 
1863a62b615Svisa static struct octeon_bootmem_block *
pa_to_block(paddr_t addr)1873a62b615Svisa pa_to_block(paddr_t addr)
1883a62b615Svisa {
1893a62b615Svisa 	return (struct octeon_bootmem_block *)PHYS_TO_XKPHYS(addr, CCA_CACHED);
1903a62b615Svisa }
1913a62b615Svisa 
192c6b2ceb4Ssyuu void
octeon_memory_init(struct boot_info * boot_info)193b9a81422Ssyuu octeon_memory_init(struct boot_info *boot_info)
194c6b2ceb4Ssyuu {
195fe08f639Svisa 	struct octeon_bootmem_block *block;
196fe08f639Svisa 	struct octeon_bootmem_desc *memdesc;
197fe08f639Svisa 	paddr_t blockaddr;
198fe08f639Svisa 	uint64_t fp, lp;
199c6b2ceb4Ssyuu 	int i;
200b9a81422Ssyuu 
201fe08f639Svisa 	physmem = atop((uint64_t)boot_info->dram_size << 20);
202b9a81422Ssyuu 
203fe08f639Svisa 	if (boot_info->phys_mem_desc_addr == 0)
204fe08f639Svisa 		panic("bootmem desc is missing");
205fe08f639Svisa 	memdesc = (struct octeon_bootmem_desc *)PHYS_TO_XKPHYS(
206fe08f639Svisa 	    boot_info->phys_mem_desc_addr, CCA_CACHED);
207fe08f639Svisa 	printf("bootmem desc 0x%x version %d.%d\n",
208fe08f639Svisa 	    boot_info->phys_mem_desc_addr, memdesc->major_version,
209fe08f639Svisa 	    memdesc->minor_version);
210fe08f639Svisa 	if (memdesc->major_version > 3)
211fe08f639Svisa 		panic("unhandled bootmem desc version %d.%d",
212fe08f639Svisa 		    memdesc->major_version, memdesc->minor_version);
213b9a81422Ssyuu 
214fe08f639Svisa 	blockaddr = memdesc->head_addr;
215fe08f639Svisa 	if (blockaddr == 0)
216fe08f639Svisa 		panic("bootmem list is empty");
217fe08f639Svisa 	for (i = 0; i < MAXMEMSEGS && blockaddr != 0; blockaddr = block->next) {
2183a62b615Svisa 		block = pa_to_block(blockaddr);
219fe08f639Svisa 		printf("avail phys mem 0x%016lx - 0x%016lx\n", blockaddr,
220fe08f639Svisa 		    (paddr_t)(blockaddr + block->size));
221fb14e7cbSsyuu 
2223a62b615Svisa #if NOCTBOOT > 0
2233a62b615Svisa 		/*
2243a62b615Svisa 		 * Reserve the physical memory below the boot kernel
2253a62b615Svisa 		 * for loading the actual kernel.
2263a62b615Svisa 		 */
2273a62b615Svisa 		extern char start[];
2283a62b615Svisa 		if (blockaddr < CKSEG_SIZE &&
2293a62b615Svisa 		    PHYS_TO_CKSEG0(blockaddr) < (vaddr_t)start) {
2303a62b615Svisa 			printf("skipped\n");
2313a62b615Svisa 			continue;
2323a62b615Svisa 		}
2333a62b615Svisa #endif
2343a62b615Svisa 
235fe08f639Svisa 		fp = atop(round_page(blockaddr));
236fe08f639Svisa 		lp = atop(trunc_page(blockaddr + block->size));
237fe08f639Svisa 
238fe08f639Svisa 		/* Clamp to the range of the pmap. */
239fe08f639Svisa 		if (fp > atop(pfn_to_pad(PG_FRAME)))
240fe08f639Svisa 			continue;
241fe08f639Svisa 		if (lp > atop(pfn_to_pad(PG_FRAME)) + 1)
242fe08f639Svisa 			lp = atop(pfn_to_pad(PG_FRAME)) + 1;
243fe08f639Svisa 		if (fp >= lp)
244fe08f639Svisa 			continue;
245fe08f639Svisa 
246252f28ffSvisa 		/* Skip small fragments. */
247252f28ffSvisa 		if (lp - fp < atop(1u << 20))
248252f28ffSvisa 			continue;
249252f28ffSvisa 
250fe08f639Svisa 		mem_layout[i].mem_first_page = fp;
251fe08f639Svisa 		mem_layout[i].mem_last_page = lp;
25216995c1bSvisa 		i++;
253c6b2ceb4Ssyuu 	}
254b9a81422Ssyuu 
255fe08f639Svisa 	printf("Total DRAM Size 0x%016llX\n",
256fe08f639Svisa 	    (uint64_t)boot_info->dram_size << 20);
257b9a81422Ssyuu 
258c6b2ceb4Ssyuu 	for (i = 0; mem_layout[i].mem_last_page; i++) {
259f47f0c33Sjasper 		printf("mem_layout[%d] page 0x%016llX -> 0x%016llX\n", i,
260e4c36ca5Spirofti 		    mem_layout[i].mem_first_page, mem_layout[i].mem_last_page);
2613a62b615Svisa 
2623a62b615Svisa #if NOCTBOOT > 0
2633a62b615Svisa 		fp = mem_layout[i].mem_first_page;
2643a62b615Svisa 		lp = mem_layout[i].mem_last_page;
2653a62b615Svisa 		if (bootmem_alloc_region(ptoa(fp), ptoa(lp) - ptoa(fp)) != 0)
2663a62b615Svisa 			panic("%s: bootmem allocation failed", __func__);
2673a62b615Svisa #endif
268c6b2ceb4Ssyuu 	}
269c6b2ceb4Ssyuu }
270c6b2ceb4Ssyuu 
271c6b2ceb4Ssyuu /*
272c6b2ceb4Ssyuu  * Do all the stuff that locore normally does before calling main().
273c6b2ceb4Ssyuu  * Reset mapping and set up mapping to hardware and init "wired" reg.
274c6b2ceb4Ssyuu  */
275c6b2ceb4Ssyuu vaddr_t
mips_init(register_t a0,register_t a1,register_t a2,register_t a3)2768e9ccc25Svisa mips_init(register_t a0, register_t a1, register_t a2, register_t a3)
277c6b2ceb4Ssyuu {
278c6b2ceb4Ssyuu 	uint prid;
279c6b2ceb4Ssyuu 	vaddr_t xtlb_handler;
28011a38f5dSvisa 	size_t len;
281c6b2ceb4Ssyuu 	int i;
282b9a81422Ssyuu 	struct boot_desc *boot_desc;
283b9a81422Ssyuu 	struct boot_info *boot_info;
284aec35e2fSvisa 	int32_t *symptr;
285cb79e5ceSvisa 	uint32_t config4;
286c6b2ceb4Ssyuu 
2875f307ed9Svisa 	extern char start[], end[];
288c6b2ceb4Ssyuu 	extern char exception[], e_exception[];
289c6b2ceb4Ssyuu 	extern void xtlb_miss;
290c6b2ceb4Ssyuu 
291b9a81422Ssyuu 	boot_desc = (struct boot_desc *)a3;
292706011a1Smiod 	boot_info = (struct boot_info *)
293706011a1Smiod 	    PHYS_TO_XKPHYS(boot_desc->boot_info_addr, CCA_CACHED);
294b9a81422Ssyuu 
29567551601Svisa 	/*
29667551601Svisa 	 * Save the pointers for future reference.
29767551601Svisa 	 * The descriptors are located outside the free memory,
29867551601Svisa 	 * and the kernel should preserve them.
29967551601Svisa 	 */
30067551601Svisa 	octeon_boot_desc = boot_desc;
30167551601Svisa 	octeon_boot_info = boot_info;
30267551601Svisa 
303c6b2ceb4Ssyuu #ifdef MULTIPROCESSOR
304c6b2ceb4Ssyuu 	/*
305c6b2ceb4Ssyuu 	 * Set curcpu address on primary processor.
306c6b2ceb4Ssyuu 	 */
307c6b2ceb4Ssyuu 	setcurcpu(&cpu_info_primary);
308c6b2ceb4Ssyuu #endif
309c6b2ceb4Ssyuu 
310c6b2ceb4Ssyuu 	/*
311fa1c4bcdSsyuu 	 * Set up early console output.
312fa1c4bcdSsyuu 	 */
3130d3d1942Ssyuu 	cn_tab = &uartcons;
314fa1c4bcdSsyuu 
315fa1c4bcdSsyuu 	/*
316c6b2ceb4Ssyuu 	 * Reserve space for the symbol table, if it exists.
317c6b2ceb4Ssyuu 	 */
318aec35e2fSvisa 	symptr = (int32_t *)roundup((vaddr_t)end, BOOTMEM_BLOCK_ALIGN);
319aec35e2fSvisa 	ssym = (char *)(vaddr_t)symptr[0];
320c6b2ceb4Ssyuu 	if (((long)ssym - (long)end) >= 0 &&
321c6b2ceb4Ssyuu 	    ((long)ssym - (long)end) <= 0x1000 &&
322c6b2ceb4Ssyuu 	    ssym[0] == ELFMAG0 && ssym[1] == ELFMAG1 &&
323c6b2ceb4Ssyuu 	    ssym[2] == ELFMAG2 && ssym[3] == ELFMAG3) {
324c6b2ceb4Ssyuu 		/* Pointers exist directly after kernel. */
325aec35e2fSvisa 		esym = (char *)(vaddr_t)symptr[1];
326c6b2ceb4Ssyuu 		ekern = esym;
327c6b2ceb4Ssyuu 	} else {
328c6b2ceb4Ssyuu 		/* Pointers aren't setup either... */
329c6b2ceb4Ssyuu 		ssym = NULL;
330c6b2ceb4Ssyuu 		esym = NULL;
331c6b2ceb4Ssyuu 		ekern = end;
332c6b2ceb4Ssyuu 	}
333c6b2ceb4Ssyuu 
334c6b2ceb4Ssyuu 	prid = cp0_get_prid();
335c6b2ceb4Ssyuu 
336b9a81422Ssyuu 	bootcpu_hwinfo.clock = boot_desc->eclock;
337c6b2ceb4Ssyuu 
33843854733Svisa 	switch (octeon_model_family(prid)) {
339358aeffeSvisa 	default:
340358aeffeSvisa 		octeon_ver = OCTEON_1;
341358aeffeSvisa 		break;
34243854733Svisa 	case OCTEON_MODEL_FAMILY_CN50XX:
343358aeffeSvisa 		octeon_ver = OCTEON_PLUS;
344358aeffeSvisa 		break;
34543854733Svisa 	case OCTEON_MODEL_FAMILY_CN61XX:
3465f3b292cSvisa 	case OCTEON_MODEL_FAMILY_CN63XX:
3475f3b292cSvisa 	case OCTEON_MODEL_FAMILY_CN66XX:
3485f3b292cSvisa 	case OCTEON_MODEL_FAMILY_CN68XX:
349358aeffeSvisa 		octeon_ver = OCTEON_2;
350358aeffeSvisa 		break;
35143854733Svisa 	case OCTEON_MODEL_FAMILY_CN71XX:
35243854733Svisa 	case OCTEON_MODEL_FAMILY_CN73XX:
3535f3b292cSvisa 	case OCTEON_MODEL_FAMILY_CN78XX:
354358aeffeSvisa 		octeon_ver = OCTEON_3;
355358aeffeSvisa 		break;
356358aeffeSvisa 	}
357358aeffeSvisa 
358c6b2ceb4Ssyuu 	/*
359c6b2ceb4Ssyuu 	 * Look at arguments passed to us and compute boothowto.
360c6b2ceb4Ssyuu 	 */
361c6b2ceb4Ssyuu 	boothowto = RB_AUTOBOOT;
362c6b2ceb4Ssyuu 
363b9a81422Ssyuu 	octeon_memory_init(boot_info);
364c6b2ceb4Ssyuu 
365c6b2ceb4Ssyuu 	/*
366c6b2ceb4Ssyuu 	 * Set pagesize to enable use of page macros and functions.
367c6b2ceb4Ssyuu 	 * Commit available memory to UVM system.
368c6b2ceb4Ssyuu 	 */
369c6b2ceb4Ssyuu 
370c6b2ceb4Ssyuu 	uvmexp.pagesize = PAGE_SIZE;
371c6b2ceb4Ssyuu 	uvm_setpagesize();
372c6b2ceb4Ssyuu 
373c6b2ceb4Ssyuu 	for (i = 0; i < MAXMEMSEGS && mem_layout[i].mem_last_page != 0; i++) {
374c6b2ceb4Ssyuu 		uint64_t fp, lp;
375c6b2ceb4Ssyuu 		uint64_t firstkernpage, lastkernpage;
376c6b2ceb4Ssyuu 		paddr_t firstkernpa, lastkernpa;
377c6b2ceb4Ssyuu 
378c6b2ceb4Ssyuu 		/* kernel is linked in CKSEG0 */
379c6b2ceb4Ssyuu 		firstkernpa = CKSEG0_TO_PHYS((vaddr_t)start);
380c6b2ceb4Ssyuu 		lastkernpa = CKSEG0_TO_PHYS((vaddr_t)ekern);
381c6b2ceb4Ssyuu 
382c6b2ceb4Ssyuu 		firstkernpage = atop(trunc_page(firstkernpa));
383c6b2ceb4Ssyuu 		lastkernpage = atop(round_page(lastkernpa));
384c6b2ceb4Ssyuu 
385c6b2ceb4Ssyuu 		fp = mem_layout[i].mem_first_page;
386c6b2ceb4Ssyuu 		lp = mem_layout[i].mem_last_page;
387c6b2ceb4Ssyuu 
388c6b2ceb4Ssyuu 		/* Account for kernel and kernel symbol table. */
389c6b2ceb4Ssyuu 		if (fp >= firstkernpage && lp < lastkernpage)
390c6b2ceb4Ssyuu 			continue;	/* In kernel. */
391c6b2ceb4Ssyuu 
392c6b2ceb4Ssyuu 		if (lp < firstkernpage || fp > lastkernpage) {
3932ce3b4a8Soga 			uvm_page_physload(fp, lp, fp, lp, 0);
394c6b2ceb4Ssyuu 			continue;	/* Outside kernel. */
395c6b2ceb4Ssyuu 		}
396c6b2ceb4Ssyuu 
397c6b2ceb4Ssyuu 		if (fp >= firstkernpage)
398c6b2ceb4Ssyuu 			fp = lastkernpage;
399c6b2ceb4Ssyuu 		else if (lp < lastkernpage)
400c6b2ceb4Ssyuu 			lp = firstkernpage;
401c6b2ceb4Ssyuu 		else { /* Need to split! */
402c6b2ceb4Ssyuu 			uint64_t xp = firstkernpage;
4032ce3b4a8Soga 			uvm_page_physload(fp, xp, fp, xp, 0);
404c6b2ceb4Ssyuu 			fp = lastkernpage;
405c6b2ceb4Ssyuu 		}
406c6b2ceb4Ssyuu 		if (lp > fp) {
4072ce3b4a8Soga 			uvm_page_physload(fp, lp, fp, lp, 0);
408c6b2ceb4Ssyuu 		}
409c6b2ceb4Ssyuu 	}
410c6b2ceb4Ssyuu 
411c6b2ceb4Ssyuu 	bootcpu_hwinfo.c0prid = prid;
412c6b2ceb4Ssyuu 	bootcpu_hwinfo.type = (prid >> 8) & 0xff;
4136d1676f7Svisa 	if (cp0_get_config_1() & CONFIG1_FP)
4146d1676f7Svisa 		bootcpu_hwinfo.c1prid = cp1_get_prid();
4156d1676f7Svisa 	else
4166d1676f7Svisa 		bootcpu_hwinfo.c1prid = 0;
417cb79e5ceSvisa 
41854efcfedSvisa 	bootcpu_hwinfo.tlbsize = 1 + ((cp0_get_config_1() & CONFIG1_MMUSize1)
41954efcfedSvisa 	    >> CONFIG1_MMUSize1_SHIFT);
420cb79e5ceSvisa 	if (cp0_get_config_3() & CONFIG3_M) {
421cb79e5ceSvisa 		config4 = cp0_get_config_4();
422cb79e5ceSvisa 		if (((config4 & CONFIG4_MMUExtDef) >>
423cb79e5ceSvisa 		    CONFIG4_MMUExtDef_SHIFT) == 1)
424cb79e5ceSvisa 			bootcpu_hwinfo.tlbsize +=
425cb79e5ceSvisa 			    (config4 & CONFIG4_MMUSizeExt) << 6;
426cb79e5ceSvisa 	}
427cb79e5ceSvisa 
428c6b2ceb4Ssyuu 	bcopy(&bootcpu_hwinfo, &curcpu()->ci_hw, sizeof(struct cpu_hwinfo));
429c6b2ceb4Ssyuu 
430c6b2ceb4Ssyuu 	/*
431c6b2ceb4Ssyuu 	 * Configure cache.
432c6b2ceb4Ssyuu 	 */
433c6b2ceb4Ssyuu 
434c6b2ceb4Ssyuu 	Octeon_ConfigCache(curcpu());
435c6b2ceb4Ssyuu 	Octeon_SyncCache(curcpu());
436c6b2ceb4Ssyuu 
4378f99340cSvisa 	octeon_tlb_init();
438c6b2ceb4Ssyuu 
439534dab3bSjasper 	snprintf(cpu_model, sizeof(cpu_model), "Cavium OCTEON (rev %d.%d) @ %d MHz",
440534dab3bSjasper 		 (bootcpu_hwinfo.c0prid >> 4) & 0x0f,
441534dab3bSjasper 		 bootcpu_hwinfo.c0prid & 0x0f,
442534dab3bSjasper 		 bootcpu_hwinfo.clock / 1000000);
443534dab3bSjasper 
444d09664daSjasper 	cpu_cpuspeed = octeon_cpuspeed;
445b5503b64Sjasper 	ncpusfound = get_ncpusfound();
4462bbf581cSvisa 	octeon_board = get_octeon_board();
447b5503b64Sjasper 
44801f63e54Sjasper 	process_bootargs();
44901f63e54Sjasper 
4507b0d27bbSjasper 	/*
4518a4f0236Svisa 	 * Save the FDT and let the system use it.
4528a4f0236Svisa 	 */
4538a4f0236Svisa 	if (octeon_boot_info->ver_minor >= 3 &&
4548a4f0236Svisa 	    octeon_boot_info->fdt_addr != 0) {
4558a4f0236Svisa 		void *fdt;
4568a4f0236Svisa 		size_t fdt_size;
4578a4f0236Svisa 
4588a4f0236Svisa 		fdt = (void *)PHYS_TO_XKPHYS(octeon_boot_info->fdt_addr,
4598a4f0236Svisa 		    CCA_CACHED);
4608a4f0236Svisa 		if (fdt_init(fdt) != 0 && (fdt_size = fdt_get_size(fdt)) != 0) {
4618a4f0236Svisa 			octeon_fdt = (void *)pmap_steal_memory(fdt_size, NULL,
4628a4f0236Svisa 			    NULL);
4638a4f0236Svisa 			memcpy(octeon_fdt, fdt, fdt_size);
4648a4f0236Svisa 			fdt_init(octeon_fdt);
4658a4f0236Svisa 		}
4666ce0dd2eSvisa 	} else
4676ce0dd2eSvisa 		fdt_init(dt_blob_start);
4688a4f0236Svisa 
4698a4f0236Svisa 	/*
470c6b2ceb4Ssyuu 	 * Get a console, very early but after initial mapping setup.
471c6b2ceb4Ssyuu 	 */
472c6b2ceb4Ssyuu 
473c6b2ceb4Ssyuu 	consinit();
474c6b2ceb4Ssyuu 	printf("Initial setup done, switching console.\n");
475c6b2ceb4Ssyuu 
476b9a81422Ssyuu #define DUMP_BOOT_DESC(field, format) \
477b9a81422Ssyuu 	printf("boot_desc->" #field ":" #format "\n", boot_desc->field)
478b9a81422Ssyuu #define DUMP_BOOT_INFO(field, format) \
479b9a81422Ssyuu 	printf("boot_info->" #field ":" #format "\n", boot_info->field)
480b9a81422Ssyuu 
481b9a81422Ssyuu 	DUMP_BOOT_DESC(desc_ver, %d);
482b9a81422Ssyuu 	DUMP_BOOT_DESC(desc_size, %d);
4830d4fbce5Sjasper 	DUMP_BOOT_DESC(stack_top, %llx);
4840d4fbce5Sjasper 	DUMP_BOOT_DESC(heap_start, %llx);
4850d4fbce5Sjasper 	DUMP_BOOT_DESC(heap_end, %llx);
486b9a81422Ssyuu 	DUMP_BOOT_DESC(argc, %d);
4877f8eec11Sjasper 	DUMP_BOOT_DESC(flags, %#x);
4887f8eec11Sjasper 	DUMP_BOOT_DESC(core_mask, %#x);
489b9a81422Ssyuu 	DUMP_BOOT_DESC(dram_size, %d);
4907f8eec11Sjasper 	DUMP_BOOT_DESC(phy_mem_desc_addr, %#x);
4917f8eec11Sjasper 	DUMP_BOOT_DESC(debugger_flag_addr, %#x);
492b9a81422Ssyuu 	DUMP_BOOT_DESC(eclock, %d);
4937f8eec11Sjasper 	DUMP_BOOT_DESC(boot_info_addr, %#llx);
494b9a81422Ssyuu 
495b9a81422Ssyuu 	DUMP_BOOT_INFO(ver_major, %d);
496b9a81422Ssyuu 	DUMP_BOOT_INFO(ver_minor, %d);
497f47f0c33Sjasper 	DUMP_BOOT_INFO(stack_top, %llx);
498f47f0c33Sjasper 	DUMP_BOOT_INFO(heap_start, %llx);
499f47f0c33Sjasper 	DUMP_BOOT_INFO(heap_end, %llx);
5007f8eec11Sjasper 	DUMP_BOOT_INFO(boot_desc_addr, %#llx);
5017f8eec11Sjasper 	DUMP_BOOT_INFO(exception_base_addr, %#x);
502b9a81422Ssyuu 	DUMP_BOOT_INFO(stack_size, %d);
5037f8eec11Sjasper 	DUMP_BOOT_INFO(flags, %#x);
5047f8eec11Sjasper 	DUMP_BOOT_INFO(core_mask, %#x);
505b9a81422Ssyuu 	DUMP_BOOT_INFO(dram_size, %d);
5067f8eec11Sjasper 	DUMP_BOOT_INFO(phys_mem_desc_addr, %#x);
5077f8eec11Sjasper 	DUMP_BOOT_INFO(debugger_flags_addr, %#x);
508b9a81422Ssyuu 	DUMP_BOOT_INFO(eclock, %d);
509b9a81422Ssyuu 	DUMP_BOOT_INFO(dclock, %d);
510b9a81422Ssyuu 	DUMP_BOOT_INFO(board_type, %d);
511b9a81422Ssyuu 	DUMP_BOOT_INFO(board_rev_major, %d);
512b9a81422Ssyuu 	DUMP_BOOT_INFO(board_rev_minor, %d);
513b9a81422Ssyuu 	DUMP_BOOT_INFO(mac_addr_count, %d);
5147f8eec11Sjasper 	DUMP_BOOT_INFO(cf_common_addr, %#llx);
5157f8eec11Sjasper 	DUMP_BOOT_INFO(cf_attr_addr, %#llx);
5167f8eec11Sjasper 	DUMP_BOOT_INFO(led_display_addr, %#llx);
517b9a81422Ssyuu 	DUMP_BOOT_INFO(dfaclock, %d);
5187f8eec11Sjasper 	DUMP_BOOT_INFO(config_flags, %#x);
5198a4f0236Svisa 	if (octeon_boot_info->ver_minor >= 3)
5208a4f0236Svisa 		DUMP_BOOT_INFO(fdt_addr, %#llx);
521b9a81422Ssyuu 
522c6b2ceb4Ssyuu 	/*
523e352a051Svisa 	 * It is possible to launch the kernel from the bootloader without
524e352a051Svisa 	 * physical CPU 0. That does not really work, however, because of the
525e352a051Svisa 	 * way how the kernel assigns and uses cpuids. Moreover, cnmac(4) is
526e352a051Svisa 	 * hard coded to use CPU 0 for packet reception.
527e352a051Svisa 	 */
528e352a051Svisa 	if (!(octeon_boot_info->core_mask & 1))
529e352a051Svisa 		panic("cannot run without physical CPU 0");
530e352a051Svisa 
531e352a051Svisa 	/*
53211a38f5dSvisa 	 * Use bits of board information to improve initial entropy.
53311a38f5dSvisa 	 */
53411a38f5dSvisa 	enqueue_randomness((octeon_boot_info->board_type << 16) |
53511a38f5dSvisa 	    (octeon_boot_info->board_rev_major << 8) |
53611a38f5dSvisa 	    octeon_boot_info->board_rev_minor);
53711a38f5dSvisa 	len = strnlen(octeon_boot_info->board_serial,
53811a38f5dSvisa 	    sizeof(octeon_boot_info->board_serial));
53911a38f5dSvisa 	for (i = 0; i < len; i++)
54011a38f5dSvisa 		enqueue_randomness(octeon_boot_info->board_serial[i]);
54111a38f5dSvisa 
54211a38f5dSvisa 	/*
543c6b2ceb4Ssyuu 	 * Init message buffer.
544c6b2ceb4Ssyuu 	 */
545c6b2ceb4Ssyuu 	msgbufbase = (caddr_t)pmap_steal_memory(MSGBUFSIZE, NULL,NULL);
546c6b2ceb4Ssyuu 	initmsgbuf(msgbufbase, MSGBUFSIZE);
547c6b2ceb4Ssyuu 
548c6b2ceb4Ssyuu 	/*
549c6b2ceb4Ssyuu 	 * Allocate U page(s) for proc[0], pm_tlbpid 1.
550c6b2ceb4Ssyuu 	 */
551c6b2ceb4Ssyuu 
552c6b2ceb4Ssyuu 	proc0.p_addr = proc0paddr = curcpu()->ci_curprocpaddr =
553c6b2ceb4Ssyuu 	    (struct user *)pmap_steal_memory(USPACE, NULL, NULL);
554b43ebd13Smpi 	proc0.p_md.md_regs = (struct trapframe *)&proc0paddr->u_pcb.pcb_regs;
555caeb30e1Smiod 	tlb_set_pid(MIN_USER_ASID);
556c6b2ceb4Ssyuu 
557c6b2ceb4Ssyuu 	/*
558c6b2ceb4Ssyuu 	 * Bootstrap VM system.
559c6b2ceb4Ssyuu 	 */
560c6b2ceb4Ssyuu 
561c6b2ceb4Ssyuu 	pmap_bootstrap();
562c6b2ceb4Ssyuu 
563c6b2ceb4Ssyuu 	/*
564c6b2ceb4Ssyuu 	 * Copy down exception vector code.
565c6b2ceb4Ssyuu 	 */
566c6b2ceb4Ssyuu 
567c6b2ceb4Ssyuu 	bcopy(exception, (char *)CACHE_ERR_EXC_VEC, e_exception - exception);
568c6b2ceb4Ssyuu 	bcopy(exception, (char *)GEN_EXC_VEC, e_exception - exception);
569c6b2ceb4Ssyuu 
570c6b2ceb4Ssyuu 	/*
571c6b2ceb4Ssyuu 	 * Build proper TLB refill handler trampolines.
572c6b2ceb4Ssyuu 	 */
573c6b2ceb4Ssyuu 
574c6b2ceb4Ssyuu 	xtlb_handler = (vaddr_t)&xtlb_miss;
575c6b2ceb4Ssyuu 	build_trampoline(TLB_MISS_EXC_VEC, xtlb_handler);
576c6b2ceb4Ssyuu 	build_trampoline(XTLB_MISS_EXC_VEC, xtlb_handler);
577c6b2ceb4Ssyuu 
578c6b2ceb4Ssyuu 	/*
579c6b2ceb4Ssyuu 	 * Turn off bootstrap exception vectors.
580c6b2ceb4Ssyuu 	 * (this is done by PMON already, but it doesn't hurt to be safe)
581c6b2ceb4Ssyuu 	 */
582c6b2ceb4Ssyuu 
583c6b2ceb4Ssyuu 	setsr(getsr() & ~SR_BOOT_EXC_VEC);
584c6b2ceb4Ssyuu 	proc0.p_md.md_regs->sr = getsr();
585c6b2ceb4Ssyuu 
586c6b2ceb4Ssyuu #ifdef DDB
587c6b2ceb4Ssyuu 	db_machine_init();
588c6b2ceb4Ssyuu 	if (boothowto & RB_KDB)
589e97088d6Smpi 		db_enter();
590c6b2ceb4Ssyuu #endif
591c6b2ceb4Ssyuu 
59239db07acSvisa 	switch (octeon_model_family(prid)) {
59339db07acSvisa 	case OCTEON_MODEL_FAMILY_CN73XX:
5949e8849fbSvisa 	case OCTEON_MODEL_FAMILY_CN78XX:
59539db07acSvisa 		ioclock_timecounter.tc_priv = (void *)FPA3_CLK_COUNT;
59639db07acSvisa 		break;
59739db07acSvisa 	default:
59839db07acSvisa 		ioclock_timecounter.tc_priv = (void *)IPD_CLK_COUNT;
59939db07acSvisa 		break;
60039db07acSvisa 	}
60139db07acSvisa 	ioclock_timecounter.tc_frequency = octeon_ioclock_speed();
60239db07acSvisa 	tc_init(&ioclock_timecounter);
603acef65c9Svisa 
6049e8849fbSvisa 	cpu_has_synced_cp0_count = 1;
6059e8849fbSvisa 	cp0_timecounter.tc_quality = 1000;
606757e7193Svisa 	cp0_timecounter.tc_user = TC_CP0_COUNT;
6079e8849fbSvisa 
608c6b2ceb4Ssyuu 	/*
609c6b2ceb4Ssyuu 	 * Return the new kernel stack pointer.
610c6b2ceb4Ssyuu 	 */
611c6b2ceb4Ssyuu 	return ((vaddr_t)proc0paddr + USPACE - 64);
612c6b2ceb4Ssyuu }
613c6b2ceb4Ssyuu 
614c6b2ceb4Ssyuu /*
615c6b2ceb4Ssyuu  * Console initialization: called early on from main, before vm init or startup.
616c6b2ceb4Ssyuu  * Do enough configuration to choose and initialize a console.
617c6b2ceb4Ssyuu  */
618c6b2ceb4Ssyuu void
consinit()619c6b2ceb4Ssyuu consinit()
620c6b2ceb4Ssyuu {
621c6b2ceb4Ssyuu 	static int console_ok = 0;
622c6b2ceb4Ssyuu 
623c6b2ceb4Ssyuu 	if (console_ok == 0) {
62423da198fSvisa 		com_fdt_init_cons();
625c6b2ceb4Ssyuu 		cninit();
626c6b2ceb4Ssyuu 		console_ok = 1;
627c6b2ceb4Ssyuu 	}
628c6b2ceb4Ssyuu }
629c6b2ceb4Ssyuu 
630c6b2ceb4Ssyuu /*
631c6b2ceb4Ssyuu  * cpu_startup: allocate memory for variable-sized tables, initialize CPU, and
632c6b2ceb4Ssyuu  * do auto-configuration.
633c6b2ceb4Ssyuu  */
634c6b2ceb4Ssyuu void
cpu_startup()635c6b2ceb4Ssyuu cpu_startup()
636c6b2ceb4Ssyuu {
637c6b2ceb4Ssyuu 	vaddr_t minaddr, maxaddr;
638c6b2ceb4Ssyuu 
639c6b2ceb4Ssyuu 	/*
640c6b2ceb4Ssyuu 	 * Good {morning,afternoon,evening,night}.
641c6b2ceb4Ssyuu 	 */
642c268af84Svisa 	printf("%s", version);
643f47f0c33Sjasper 	printf("real mem = %lu (%luMB)\n", ptoa((psize_t)physmem),
644c6b2ceb4Ssyuu 	    ptoa((psize_t)physmem)/1024/1024);
645c6b2ceb4Ssyuu 
646c6b2ceb4Ssyuu 	/*
647c6b2ceb4Ssyuu 	 * Allocate a submap for exec arguments. This map effectively
648c6b2ceb4Ssyuu 	 * limits the number of processes exec'ing at any time.
649c6b2ceb4Ssyuu 	 */
650c6b2ceb4Ssyuu 	minaddr = vm_map_min(kernel_map);
651c6b2ceb4Ssyuu 	exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
652c6b2ceb4Ssyuu 	    16 * NCARGS, VM_MAP_PAGEABLE, FALSE, NULL);
653c6b2ceb4Ssyuu 	/* Allocate a submap for physio. */
654c6b2ceb4Ssyuu 	phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
655c6b2ceb4Ssyuu 	    VM_PHYS_SIZE, 0, FALSE, NULL);
656c6b2ceb4Ssyuu 
657f47f0c33Sjasper 	printf("avail mem = %lu (%luMB)\n", ptoa(uvmexp.free),
658c6b2ceb4Ssyuu 	    ptoa(uvmexp.free)/1024/1024);
659c6b2ceb4Ssyuu 
660c6b2ceb4Ssyuu 	/*
661c6b2ceb4Ssyuu 	 * Set up buffers, so they can be used to read disk labels.
662c6b2ceb4Ssyuu 	 */
663c6b2ceb4Ssyuu 	bufinit();
664c6b2ceb4Ssyuu 
665c6b2ceb4Ssyuu 	/*
666c6b2ceb4Ssyuu 	 * Configure the system.
667c6b2ceb4Ssyuu 	 */
668c6b2ceb4Ssyuu 	if (boothowto & RB_CONFIG) {
669c6b2ceb4Ssyuu #ifdef BOOT_CONFIG
670c6b2ceb4Ssyuu 		user_config();
671c6b2ceb4Ssyuu #else
672c6b2ceb4Ssyuu 		printf("kernel does not support -c; continuing..\n");
673c6b2ceb4Ssyuu #endif
674c6b2ceb4Ssyuu 	}
675c6b2ceb4Ssyuu }
676c6b2ceb4Ssyuu 
677d09664daSjasper int
octeon_cpuspeed(int * freq)678d09664daSjasper octeon_cpuspeed(int *freq)
679d09664daSjasper {
680d09664daSjasper 	*freq = octeon_boot_info->eclock / 1000000;
681d09664daSjasper 	return (0);
682d09664daSjasper }
683d09664daSjasper 
6845f139a3aSjmatthew int
octeon_ioclock_speed(void)6855f139a3aSjmatthew octeon_ioclock_speed(void)
6865f139a3aSjmatthew {
68703c3188dSvisa 	u_int64_t mio_rst_boot, rst_boot;
6885f139a3aSjmatthew 
689358aeffeSvisa 	switch (octeon_ver) {
690358aeffeSvisa 	case OCTEON_2:
6915f139a3aSjmatthew 		mio_rst_boot = octeon_xkphys_read_8(MIO_RST_BOOT);
6925f139a3aSjmatthew 		return OCTEON_IO_REF_CLOCK * ((mio_rst_boot >>
6935f139a3aSjmatthew 		    MIO_RST_BOOT_PNR_MUL_SHIFT) & MIO_RST_BOOT_PNR_MUL_MASK);
694358aeffeSvisa 	case OCTEON_3:
69503c3188dSvisa 		rst_boot = octeon_xkphys_read_8(RST_BOOT);
69603c3188dSvisa 		return OCTEON_IO_REF_CLOCK * ((rst_boot >>
69703c3188dSvisa 		    RST_BOOT_PNR_MUL_SHIFT) & RST_BOOT_PNR_MUL_MASK);
6985f139a3aSjmatthew 	default:
6995f139a3aSjmatthew 		return octeon_boot_info->eclock;
7005f139a3aSjmatthew 	}
7015f139a3aSjmatthew }
7025f139a3aSjmatthew 
7038f99340cSvisa void
octeon_tlb_init(void)7048f99340cSvisa octeon_tlb_init(void)
7058f99340cSvisa {
7069e8849fbSvisa 	uint64_t clk_reg, cvmmemctl, frac, cmul, imul, val;
7072fef4a92Svisa 	uint32_t hwrena = 0;
7088f99340cSvisa 	uint32_t pgrain = 0;
709f4fee9beSvisa 	int chipid;
710f4fee9beSvisa 
711f4fee9beSvisa 	chipid = octeon_get_chipid();
712f4fee9beSvisa 	switch (octeon_model_family(chipid)) {
713f4fee9beSvisa 	case OCTEON_MODEL_FAMILY_CN73XX:
714f4fee9beSvisa 		/* Enable LMTDMA/LMTST transactions. */
715f4fee9beSvisa 		cvmmemctl = octeon_get_cvmmemctl();
716f4fee9beSvisa 		cvmmemctl |= COP_0_CVMMEMCTL_LMTENA;
717f4fee9beSvisa 		cvmmemctl &= ~COP_0_CVMMEMCTL_LMTLINE_M;
718f4fee9beSvisa 		cvmmemctl |= 2ull << COP_0_CVMMEMCTL_LMTLINE_S;
719f4fee9beSvisa 		octeon_set_cvmmemctl(cvmmemctl);
720f4fee9beSvisa 		break;
721f4fee9beSvisa 	}
7228f99340cSvisa 
7232fef4a92Svisa 	/*
724d4086a48Svisa 	 * Make sure Coprocessor 2 is disabled.
725d4086a48Svisa 	 */
726d4086a48Svisa 	setsr(getsr() & ~SR_COP_2_BIT);
727d4086a48Svisa 
728d4086a48Svisa 	/*
7299e8849fbSvisa 	 * Synchronize this core's cycle counter with the system-wide
7309e8849fbSvisa 	 * IO clock counter.
7319e8849fbSvisa 	 *
7329e8849fbSvisa 	 * The IO clock counter's value has to be scaled from the IO clock
7339e8849fbSvisa 	 * frequency domain to the core clock frequency domain:
7349e8849fbSvisa 	 *
7359e8849fbSvisa 	 * cclk / cmul = iclk / imul
7369e8849fbSvisa 	 * cclk = iclk * cmul / imul
7379e8849fbSvisa 	 *
7389e8849fbSvisa 	 * Division is very slow and possibly variable-time on the system,
7399e8849fbSvisa 	 * so the synchronization routine uses multiplication:
7409e8849fbSvisa 	 *
7419e8849fbSvisa 	 * cclk = iclk * cmul * frac / 2^64,
7429e8849fbSvisa 	 *
7439e8849fbSvisa 	 * where frac = 2^64 / imul is precomputed.
7449e8849fbSvisa 	 */
7459e8849fbSvisa 	switch (octeon_model_family(chipid)) {
7469e8849fbSvisa 	case OCTEON_MODEL_FAMILY_CN73XX:
7479e8849fbSvisa 	case OCTEON_MODEL_FAMILY_CN78XX:
7489e8849fbSvisa 		clk_reg = FPA3_CLK_COUNT;
7499e8849fbSvisa 		break;
7509e8849fbSvisa 	default:
7519e8849fbSvisa 		clk_reg = IPD_CLK_COUNT;
7529e8849fbSvisa 		break;
7539e8849fbSvisa 	}
7549e8849fbSvisa 	switch (octeon_ver) {
7559e8849fbSvisa 	case OCTEON_2:
7569e8849fbSvisa 		val = octeon_xkphys_read_8(MIO_RST_BOOT);
7579e8849fbSvisa 		cmul = (val >> MIO_RST_BOOT_C_MUL_SHIFT) &
7589e8849fbSvisa 		    MIO_RST_BOOT_C_MUL_MASK;
7599e8849fbSvisa 		imul = (val >> MIO_RST_BOOT_PNR_MUL_SHIFT) &
7609e8849fbSvisa 		    MIO_RST_BOOT_PNR_MUL_MASK;
7619e8849fbSvisa 		break;
7629e8849fbSvisa 	case OCTEON_3:
7639e8849fbSvisa 		val = octeon_xkphys_read_8(RST_BOOT);
7649e8849fbSvisa 		cmul = (val >> RST_BOOT_C_MUL_SHIFT) &
7659e8849fbSvisa 		    RST_BOOT_C_MUL_MASK;
7669e8849fbSvisa 		imul = (val >> RST_BOOT_PNR_MUL_SHIFT) &
7679e8849fbSvisa 		    RST_BOOT_PNR_MUL_MASK;
7689e8849fbSvisa 		break;
7699e8849fbSvisa 	default:
7709e8849fbSvisa 		cmul = 1;
7719e8849fbSvisa 		imul = 1;
7729e8849fbSvisa 		break;
7739e8849fbSvisa 	}
7749e8849fbSvisa 	frac = ((1ULL << 63) / imul) * 2;
7759e8849fbSvisa 	octeon_sync_tc(PHYS_TO_XKPHYS(clk_reg, CCA_NC), cmul, frac);
7769e8849fbSvisa 
777757e7193Svisa 	/* Let userspace access the cycle counter. */
778757e7193Svisa 	hwrena |= HWRENA_CC;
779757e7193Svisa 
7809e8849fbSvisa 	/*
7812fef4a92Svisa 	 * If the UserLocal register is available, let userspace
7822fef4a92Svisa 	 * access it using the RDHWR instruction.
7832fef4a92Svisa 	 */
7842fef4a92Svisa 	if (cp0_get_config_3() & CONFIG3_ULRI) {
7852fef4a92Svisa 		cp0_set_userlocal(NULL);
7862fef4a92Svisa 		hwrena |= HWRENA_ULR;
7872fef4a92Svisa 		cpu_has_userlocal = 1;
7882fef4a92Svisa 	}
7892fef4a92Svisa 	cp0_set_hwrena(hwrena);
7902fef4a92Svisa 
7918f99340cSvisa #ifdef MIPS_PTE64
7928f99340cSvisa 	pgrain |= PGRAIN_ELPA;
7938f99340cSvisa #endif
7948f99340cSvisa 	if (cp0_get_config_3() & CONFIG3_RXI)
79557919513Svisa 		pgrain |= (PGRAIN_RIE | PGRAIN_XIE);
7968f99340cSvisa 	cp0_set_pagegrain(pgrain);
7978f99340cSvisa 
7988f99340cSvisa 	tlb_init(bootcpu_hwinfo.tlbsize);
7998f99340cSvisa }
8008f99340cSvisa 
801b5503b64Sjasper static u_int64_t
get_ncpusfound(void)802b5503b64Sjasper get_ncpusfound(void)
803b5503b64Sjasper {
8040fee2420Svisa 	uint64_t core_mask;
8052bb91ab4Svisa 	uint64_t i, ncpus = 0;
8060fee2420Svisa 	int chipid;
8070fee2420Svisa 
8080fee2420Svisa 	chipid = octeon_get_chipid();
8090fee2420Svisa 	switch (octeon_model_family(chipid)) {
8100fee2420Svisa 	case OCTEON_MODEL_FAMILY_CN73XX:
8110fee2420Svisa 	case OCTEON_MODEL_FAMILY_CN78XX:
8120fee2420Svisa 		core_mask = octeon_xkphys_read_8(OCTEON_CIU3_BASE + CIU3_FUSE);
8130fee2420Svisa 		break;
8140fee2420Svisa 	default:
8150fee2420Svisa 		core_mask = octeon_xkphys_read_8(OCTEON_CIU_BASE + CIU_FUSE);
8160fee2420Svisa 		break;
8170fee2420Svisa 	}
818b5503b64Sjasper 
8192bb91ab4Svisa 	/* There has to be 1-to-1 mapping between cpuids and coreids. */
8202bb91ab4Svisa 	for (i = 0; i < OCTEON_MAXCPUS && (core_mask & (1ul << i)) != 0; i++)
821b5503b64Sjasper 		ncpus++;
822b5503b64Sjasper 
823b5503b64Sjasper 	return ncpus;
824b5503b64Sjasper }
82501f63e54Sjasper 
8262bbf581cSvisa static enum octeon_board
get_octeon_board(void)8272bbf581cSvisa get_octeon_board(void)
8282bbf581cSvisa {
8292bbf581cSvisa 	switch (octeon_boot_info->board_type) {
8302bbf581cSvisa 	case 11:
8312bbf581cSvisa 		return BOARD_CN3010_EVB_HS5;
8322bbf581cSvisa 	case 20002:
8332bbf581cSvisa 		return BOARD_UBIQUITI_E100;
8342bbf581cSvisa 	case 20003:
8352bbf581cSvisa 		return BOARD_UBIQUITI_E200;
8362bbf581cSvisa 	case 20004:
837133fffbaSvisa 		/* E120 has two cores, whereas UTM25 has one core. */
838133fffbaSvisa 		if (ncpusfound == 1)
839133fffbaSvisa 			return BOARD_NETGEAR_UTM25;
8402bbf581cSvisa 		return BOARD_UBIQUITI_E120;
8412bbf581cSvisa 	case 20005:
8422bbf581cSvisa 		return BOARD_UBIQUITI_E220;
8432bbf581cSvisa 	case 20010:
8442bbf581cSvisa 		return BOARD_UBIQUITI_E1000;
8454d62617aSvisa 	case 20011:
8464d62617aSvisa 		return BOARD_CHECKPOINT_N100;
8472bbf581cSvisa 	case 20012:
8482bbf581cSvisa 		return BOARD_RHINOLABS_UTM8;
8492bbf581cSvisa 	case 20015:
8502bbf581cSvisa 		return BOARD_DLINK_DSR_500;
8512bbf581cSvisa 	case 20300:
8522bbf581cSvisa 		return BOARD_UBIQUITI_E300;
8532bbf581cSvisa 	default:
8542bbf581cSvisa 		break;
8552bbf581cSvisa 	}
8562bbf581cSvisa 
8572bbf581cSvisa 	return BOARD_UNKNOWN;
8582bbf581cSvisa }
8592bbf581cSvisa 
86001f63e54Sjasper static void
process_bootargs(void)86101f63e54Sjasper process_bootargs(void)
86201f63e54Sjasper {
863b0d26ac0Svisa 	const char *cp;
864b0d26ac0Svisa 	int i;
86501f63e54Sjasper 
86601f63e54Sjasper 	/*
8672a3d5f25Smartijn 	 * U-Boot doesn't pass us anything by default, we need to explicitly
8682a3d5f25Smartijn 	 * pass the rootdevice.
86901f63e54Sjasper 	 */
8702a3d5f25Smartijn 	for (i = 0; i < octeon_boot_desc->argc; i++ ) {
871706011a1Smiod 		const char *arg = (const char*)
872706011a1Smiod 		    PHYS_TO_XKPHYS(octeon_boot_desc->argv[i], CCA_CACHED);
87301f63e54Sjasper 
874706011a1Smiod 		if (octeon_boot_desc->argv[i] == 0)
87501f63e54Sjasper 			continue;
87601f63e54Sjasper 
87701f63e54Sjasper #ifdef DEBUG
878706011a1Smiod 		printf("boot_desc->argv[%d] = %s\n", i, arg);
87901f63e54Sjasper #endif
88001f63e54Sjasper 
881a084a2f8Svisa 		if (strncmp(arg, "boothowto=", 10) == 0) {
882a084a2f8Svisa 			boothowto = atoi(arg + 10);
883a084a2f8Svisa 			continue;
884a084a2f8Svisa 		}
885a084a2f8Svisa 
8867595788fSjasper 		if (strncmp(arg, "rootdev=", 8) == 0) {
88770c43862Svisa 			parse_uboot_root(arg + 8);
88870c43862Svisa 			continue;
88901f63e54Sjasper 		}
890b0d26ac0Svisa 
891b0d26ac0Svisa 		if (*arg != '-')
892b0d26ac0Svisa 			continue;
893b0d26ac0Svisa 
894b0d26ac0Svisa 		for (cp = arg + 1; *cp != '\0'; cp++) {
895b0d26ac0Svisa 			switch (*cp) {
896b0d26ac0Svisa 			case '-':
897b0d26ac0Svisa 				break;
898b0d26ac0Svisa 			case 'a':
899b0d26ac0Svisa 				boothowto |= RB_ASKNAME;
900b0d26ac0Svisa 				break;
901b0d26ac0Svisa 			case 'c':
902b0d26ac0Svisa 				boothowto |= RB_CONFIG;
903b0d26ac0Svisa 				break;
904b0d26ac0Svisa 			case 'd':
905b0d26ac0Svisa 				boothowto |= RB_KDB;
906b0d26ac0Svisa 				break;
907b0d26ac0Svisa 			case 's':
908b0d26ac0Svisa 				boothowto |= RB_SINGLE;
909b0d26ac0Svisa 				break;
910b0d26ac0Svisa 			default:
911b0d26ac0Svisa 				printf("unrecognized option `%c'", *cp);
912b0d26ac0Svisa 				break;
913b0d26ac0Svisa 			}
914b0d26ac0Svisa 		}
91501f63e54Sjasper 	}
91601f63e54Sjasper }
91701f63e54Sjasper 
918c6b2ceb4Ssyuu /*
919c6b2ceb4Ssyuu  * Machine dependent system variables.
920c6b2ceb4Ssyuu  */
921c6b2ceb4Ssyuu int
cpu_sysctl(int * name,u_int namelen,void * oldp,size_t * oldlenp,void * newp,size_t newlen,struct proc * p)922e262726eSfcambus cpu_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
923e262726eSfcambus     size_t newlen, struct proc *p)
924c6b2ceb4Ssyuu {
925c6b2ceb4Ssyuu 	/* All sysctl names at this level are terminal. */
926c6b2ceb4Ssyuu 	if (namelen != 1)
927c6b2ceb4Ssyuu 		return ENOTDIR;		/* Overloaded */
928c6b2ceb4Ssyuu 
929c6b2ceb4Ssyuu 	switch (name[0]) {
930c6b2ceb4Ssyuu 	default:
931c6b2ceb4Ssyuu 		return EOPNOTSUPP;
932c6b2ceb4Ssyuu 	}
933c6b2ceb4Ssyuu }
934c6b2ceb4Ssyuu 
935c6b2ceb4Ssyuu int	waittime = -1;
936c6b2ceb4Ssyuu 
937ff261808Suebayasi __dead void
boot(int howto)938c6b2ceb4Ssyuu boot(int howto)
939c6b2ceb4Ssyuu {
9403c291078Stedu 	if ((howto & RB_RESET) != 0)
9413c291078Stedu 		goto doreset;
9423c291078Stedu 
943c6b2ceb4Ssyuu 	if (curproc)
944c6b2ceb4Ssyuu 		savectx(curproc->p_addr, 0);
945c6b2ceb4Ssyuu 
946c6b2ceb4Ssyuu 	if (cold) {
947c6b2ceb4Ssyuu 		if ((howto & RB_USERREQ) == 0)
948c6b2ceb4Ssyuu 			howto |= RB_HALT;
949c6b2ceb4Ssyuu 		goto haltsys;
950c6b2ceb4Ssyuu 	}
951c6b2ceb4Ssyuu 
952c6b2ceb4Ssyuu 	boothowto = howto;
953c6b2ceb4Ssyuu 	if ((howto & RB_NOSYNC) == 0 && waittime < 0) {
954c6b2ceb4Ssyuu 		waittime = 0;
9557efda1a1Sderaadt 		vfs_shutdown(curproc);
956c6b2ceb4Ssyuu 
957c6b2ceb4Ssyuu 		if ((howto & RB_TIMEBAD) == 0) {
958c6b2ceb4Ssyuu 			resettodr();
959c6b2ceb4Ssyuu 		} else {
960c6b2ceb4Ssyuu 			printf("WARNING: not updating battery clock\n");
961c6b2ceb4Ssyuu 		}
962c6b2ceb4Ssyuu 	}
9637d9ca166Sderaadt 	if_downall();
964c6b2ceb4Ssyuu 
965c6b2ceb4Ssyuu 	uvm_shutdown();
9669f43f03fSuebayasi 	splhigh();
96780ce5a38Smpi 	cold = 1;
968c6b2ceb4Ssyuu 
969b33b2f20Suebayasi 	if ((howto & RB_DUMP) != 0)
970c6b2ceb4Ssyuu 		dumpsys();
971c6b2ceb4Ssyuu 
972c6b2ceb4Ssyuu haltsys:
97396f419e1Skettenis 	config_suspend_all(DVACT_POWERDOWN);
974c6b2ceb4Ssyuu 
975b33b2f20Suebayasi 	if ((howto & RB_HALT) != 0) {
976b33b2f20Suebayasi 		if ((howto & RB_POWERDOWN) != 0)
977c6b2ceb4Ssyuu 			printf("System Power Down not supported,"
978c6b2ceb4Ssyuu 			" halting system.\n");
979c6b2ceb4Ssyuu 		else
980c6b2ceb4Ssyuu 			printf("System Halt.\n");
981c6b2ceb4Ssyuu 	} else {
9823c291078Stedu doreset:
983c6b2ceb4Ssyuu 		printf("System restart.\n");
984c6b2ceb4Ssyuu 		(void)disableintr();
985c6b2ceb4Ssyuu 		tlb_set_wired(0);
986c6b2ceb4Ssyuu 		tlb_flush(bootcpu_hwinfo.tlbsize);
98703c3188dSvisa 
988358aeffeSvisa 		if (octeon_ver == OCTEON_3)
98903c3188dSvisa 			octeon_xkphys_write_8(RST_SOFT_RST, 1);
990358aeffeSvisa 		else
99103c3188dSvisa 			octeon_xkphys_write_8(OCTEON_CIU_BASE +
99203c3188dSvisa 			    CIU_SOFT_RST, 1);
993c6b2ceb4Ssyuu 	}
994c6b2ceb4Ssyuu 
995de5ed823Stom 	for (;;)
996de5ed823Stom 		continue;
997c6b2ceb4Ssyuu 	/* NOTREACHED */
998c6b2ceb4Ssyuu }
999c6b2ceb4Ssyuu 
1000c6b2ceb4Ssyuu u_long	dumpmag = 0x8fca0101;	/* Magic number for savecore. */
1001c6b2ceb4Ssyuu int	dumpsize = 0;			/* Also for savecore. */
1002c6b2ceb4Ssyuu long	dumplo = 0;
1003c6b2ceb4Ssyuu 
1004c6b2ceb4Ssyuu void
dumpconf(void)1005c6b2ceb4Ssyuu dumpconf(void)
1006c6b2ceb4Ssyuu {
1007c6b2ceb4Ssyuu 	int nblks;
1008c6b2ceb4Ssyuu 
1009c6b2ceb4Ssyuu 	if (dumpdev == NODEV ||
1010c6b2ceb4Ssyuu 	    (nblks = (bdevsw[major(dumpdev)].d_psize)(dumpdev)) == 0)
1011c6b2ceb4Ssyuu 		return;
1012c6b2ceb4Ssyuu 	if (nblks <= ctod(1))
1013c6b2ceb4Ssyuu 		return;
1014c6b2ceb4Ssyuu 
1015c6b2ceb4Ssyuu 	dumpsize = ptoa(physmem);
1016c6b2ceb4Ssyuu 	if (dumpsize > atop(round_page(dbtob(nblks - dumplo))))
1017c6b2ceb4Ssyuu 		dumpsize = atop(round_page(dbtob(nblks - dumplo)));
1018c6b2ceb4Ssyuu 	else if (dumplo == 0)
1019c6b2ceb4Ssyuu 		dumplo = nblks - btodb(ptoa(physmem));
1020c6b2ceb4Ssyuu 
1021c6b2ceb4Ssyuu 	/*
1022c6b2ceb4Ssyuu 	 * Don't dump on the first page in case the dump device includes a
1023c6b2ceb4Ssyuu 	 * disk label.
1024c6b2ceb4Ssyuu 	 */
1025c6b2ceb4Ssyuu 	if (dumplo < btodb(PAGE_SIZE))
1026c6b2ceb4Ssyuu 		dumplo = btodb(PAGE_SIZE);
1027c6b2ceb4Ssyuu }
1028c6b2ceb4Ssyuu 
1029c6b2ceb4Ssyuu void
dumpsys()1030c6b2ceb4Ssyuu dumpsys()
1031c6b2ceb4Ssyuu {
1032c6b2ceb4Ssyuu 	/* XXX TBD */
1033c6b2ceb4Ssyuu }
1034c6b2ceb4Ssyuu 
103594483548Svisa int
is_memory_range(paddr_t pa,psize_t len,psize_t limit)1036c6b2ceb4Ssyuu is_memory_range(paddr_t pa, psize_t len, psize_t limit)
1037c6b2ceb4Ssyuu {
10380b81d999Svisa 	extern char start[];
1039c6b2ceb4Ssyuu 	struct phys_mem_desc *seg;
1040c6b2ceb4Ssyuu 	uint64_t fp, lp;
1041c6b2ceb4Ssyuu 	int i;
1042c6b2ceb4Ssyuu 
1043c6b2ceb4Ssyuu 	fp = atop(pa);
1044c6b2ceb4Ssyuu 	lp = atop(round_page(pa + len));
1045c6b2ceb4Ssyuu 
1046c6b2ceb4Ssyuu 	if (limit != 0 && lp > atop(limit))
104794483548Svisa 		return 0;
1048c6b2ceb4Ssyuu 
10490b81d999Svisa 	/* The kernel is linked in CKSEG0. */
10500b81d999Svisa 	if (fp >= atop(trunc_page(CKSEG0_TO_PHYS((vaddr_t)start))) &&
10510b81d999Svisa 	    lp <= atop(round_page(CKSEG0_TO_PHYS((vaddr_t)ekern))))
105294483548Svisa 		return 1;
10530b81d999Svisa 
1054c6b2ceb4Ssyuu 	for (i = 0, seg = mem_layout; i < MAXMEMSEGS; i++, seg++)
1055c6b2ceb4Ssyuu 		if (fp >= seg->mem_first_page && lp <= seg->mem_last_page)
105694483548Svisa 			return 1;
1057c6b2ceb4Ssyuu 
105894483548Svisa 	return 0;
1059c6b2ceb4Ssyuu }
1060c6b2ceb4Ssyuu 
1061acef65c9Svisa u_int
ioclock_get_timecount(struct timecounter * tc)106239db07acSvisa ioclock_get_timecount(struct timecounter *tc)
1063acef65c9Svisa {
106439db07acSvisa 	uint64_t reg = (uint64_t)tc->tc_priv;
106539db07acSvisa 
106639db07acSvisa 	return octeon_xkphys_read_8(reg);
1067acef65c9Svisa }
1068acef65c9Svisa 
10693a62b615Svisa #if NOCTBOOT > 0
10703a62b615Svisa static uint64_t
size_trunc(uint64_t size)10713a62b615Svisa size_trunc(uint64_t size)
10723a62b615Svisa {
10733a62b615Svisa 	return (size & ~BOOTMEM_BLOCK_MASK);
10743a62b615Svisa }
10753a62b615Svisa 
10763a62b615Svisa void
bootmem_dump(void)10773a62b615Svisa bootmem_dump(void)
10783a62b615Svisa {
10793a62b615Svisa 	struct octeon_bootmem_desc *memdesc = (struct octeon_bootmem_desc *)
10803a62b615Svisa 	    PHYS_TO_XKPHYS(octeon_boot_info->phys_mem_desc_addr, CCA_CACHED);
10813a62b615Svisa 	struct octeon_bootmem_block *block;
10823a62b615Svisa 	paddr_t pa;
10833a62b615Svisa 
10843a62b615Svisa 	pa = memdesc->head_addr;
10853a62b615Svisa 	while (pa != 0) {
10863a62b615Svisa 		block = pa_to_block(pa);
10873a62b615Svisa 		printf("free 0x%lx - 0x%lx\n", pa, pa + (size_t)block->size);
10883a62b615Svisa 		pa = block->next;
10893a62b615Svisa 	}
10903a62b615Svisa }
10913a62b615Svisa 
10923a62b615Svisa /*
10933a62b615Svisa  * Allocate the given region from the free memory list.
10943a62b615Svisa  */
10953a62b615Svisa int
bootmem_alloc_region(paddr_t pa,size_t size)10963a62b615Svisa bootmem_alloc_region(paddr_t pa, size_t size)
10973a62b615Svisa {
10983a62b615Svisa 	struct octeon_bootmem_desc *memdesc = (struct octeon_bootmem_desc *)
10993a62b615Svisa 	    PHYS_TO_XKPHYS(octeon_boot_info->phys_mem_desc_addr, CCA_CACHED);
11003a62b615Svisa 	struct octeon_bootmem_block *block, *next, nblock;
11013a62b615Svisa 	paddr_t bpa;
11023a62b615Svisa 
11033a62b615Svisa 	if (pa == 0 || size < BOOTMEM_BLOCK_MIN_SIZE ||
11043a62b615Svisa 	    (pa & BOOTMEM_BLOCK_MASK) != 0 ||
11053a62b615Svisa 	    (size & BOOTMEM_BLOCK_MASK) != 0)
11063a62b615Svisa 		return EINVAL;
11073a62b615Svisa 
11083a62b615Svisa 	if (memdesc->head_addr == 0 || pa < memdesc->head_addr)
11093a62b615Svisa 		return ENOMEM;
11103a62b615Svisa 
11113a62b615Svisa 	/* Check if the region is at the head of the free list. */
11123a62b615Svisa 	if (pa == memdesc->head_addr) {
11133a62b615Svisa 		block = pa_to_block(memdesc->head_addr);
11143a62b615Svisa 		if (block->size < size)
11153a62b615Svisa 			return ENOMEM;
11163a62b615Svisa 		if (size_trunc(block->size) == size) {
11173a62b615Svisa 			memdesc->head_addr = block->next;
11183a62b615Svisa 		} else {
11193a62b615Svisa 			KASSERT(block->size > size);
11203a62b615Svisa 			nblock.next = block->next;
11213a62b615Svisa 			nblock.size = block->size - size;
11223a62b615Svisa 			KASSERT(nblock.size >= BOOTMEM_BLOCK_MIN_SIZE);
11233a62b615Svisa 			memdesc->head_addr += size;
11243a62b615Svisa 			*pa_to_block(memdesc->head_addr) = nblock;
11253a62b615Svisa 		}
11263a62b615Svisa 		return 0;
11273a62b615Svisa 	}
11283a62b615Svisa 
11293a62b615Svisa 	/* Find the block that immediately precedes or is at `pa'. */
11303a62b615Svisa 	bpa = memdesc->head_addr;
11313a62b615Svisa 	block = pa_to_block(bpa);
11323a62b615Svisa 	while (block->next != 0 && block->next < pa) {
11333a62b615Svisa 		bpa = block->next;
11343a62b615Svisa 		block = pa_to_block(bpa);
11353a62b615Svisa 	}
11363a62b615Svisa 
11373a62b615Svisa 	/* Refuse to play if the block is not properly aligned. */
11383a62b615Svisa 	if ((bpa & BOOTMEM_BLOCK_MASK) != 0)
11393a62b615Svisa 		return ENOMEM;
11403a62b615Svisa 
11413a62b615Svisa 	if (block->next == pa) {
11423a62b615Svisa 		next = pa_to_block(block->next);
11433a62b615Svisa 		if (next->size < size)
11443a62b615Svisa 			return ENOMEM;
11453a62b615Svisa 		if (size_trunc(next->size) == size) {
11463a62b615Svisa 			block->next = next->next;
11473a62b615Svisa 		} else {
11483a62b615Svisa 			KASSERT(next->size > size);
11493a62b615Svisa 			nblock.next = next->next;
11503a62b615Svisa 			nblock.size = next->size - size;
11513a62b615Svisa 			KASSERT(nblock.size >= BOOTMEM_BLOCK_MIN_SIZE);
11523a62b615Svisa 			block->next += size;
11533a62b615Svisa 			*pa_to_block(block->next) = nblock;
11543a62b615Svisa 		}
11553a62b615Svisa 	} else {
11563a62b615Svisa 		KASSERT(bpa < pa);
11573a62b615Svisa 		KASSERT(block->next == 0 || block->next > pa);
11583a62b615Svisa 
11593a62b615Svisa 		if (bpa + block->size < pa + size)
11603a62b615Svisa 			return ENOMEM;
11613a62b615Svisa 		if (bpa + size_trunc(block->size) == pa + size) {
11623a62b615Svisa 			block->size = pa - bpa;
11633a62b615Svisa 		} else {
11643a62b615Svisa 			KASSERT(bpa + block->size > pa + size);
11653a62b615Svisa 			nblock.next = block->next;
11663a62b615Svisa 			nblock.size = block->size - (pa - bpa) - size;
11673a62b615Svisa 			KASSERT(nblock.size >= BOOTMEM_BLOCK_MIN_SIZE);
11683a62b615Svisa 			block->next = pa + size;
11693a62b615Svisa 			block->size = pa - bpa;
11703a62b615Svisa 			*pa_to_block(block->next) = nblock;
11713a62b615Svisa 		}
11723a62b615Svisa 	}
11733a62b615Svisa 
11743a62b615Svisa 	return 0;
11753a62b615Svisa }
11763a62b615Svisa 
11773a62b615Svisa /*
11783a62b615Svisa  * Release the given region to the free memory list.
11793a62b615Svisa  */
11803a62b615Svisa void
bootmem_free(paddr_t pa,size_t size)11813a62b615Svisa bootmem_free(paddr_t pa, size_t size)
11823a62b615Svisa {
11833a62b615Svisa 	struct octeon_bootmem_desc *memdesc = (struct octeon_bootmem_desc *)
11843a62b615Svisa 	    PHYS_TO_XKPHYS(octeon_boot_info->phys_mem_desc_addr, CCA_CACHED);
11853a62b615Svisa 	struct octeon_bootmem_block *block, *next, *prev;
11863a62b615Svisa 	paddr_t prevpa;
11873a62b615Svisa 
11883a62b615Svisa 	if (pa == 0 || size < BOOTMEM_BLOCK_MIN_SIZE ||
11893a62b615Svisa 	    (pa & BOOTMEM_BLOCK_MASK) != 0 ||
11903a62b615Svisa 	    (size & BOOTMEM_BLOCK_MASK) != 0)
11913a62b615Svisa 		panic("%s: invalid block 0x%lx @ 0x%lx", __func__, size, pa);
11923a62b615Svisa 
11933a62b615Svisa 	/* If the list is empty, insert at the head. */
11943a62b615Svisa 	if (memdesc->head_addr == 0) {
11953a62b615Svisa 		block = pa_to_block(pa);
11963a62b615Svisa 		block->next = 0;
11973a62b615Svisa 		block->size = size;
11983a62b615Svisa 		memdesc->head_addr = pa;
11993a62b615Svisa 		return;
12003a62b615Svisa 	}
12013a62b615Svisa 
12023a62b615Svisa 	/* If the block precedes the current head, insert before, or merge. */
12033a62b615Svisa 	if (pa <= memdesc->head_addr) {
12043a62b615Svisa 		block = pa_to_block(pa);
12053a62b615Svisa 		if (pa + size < memdesc->head_addr) {
12063a62b615Svisa 			block->next = memdesc->head_addr;
12073a62b615Svisa 			block->size = size;
12083a62b615Svisa 			memdesc->head_addr = pa;
12093a62b615Svisa 		} else if (pa + size == memdesc->head_addr) {
12103a62b615Svisa 			next = pa_to_block(memdesc->head_addr);
12113a62b615Svisa 			block->next = next->next;
12123a62b615Svisa 			block->size = next->size + size;
12133a62b615Svisa 			memdesc->head_addr = pa;
12143a62b615Svisa 		} else {
12153a62b615Svisa 			panic("%s: overlap 1: 0x%lx @ 0x%lx / 0x%llx @ 0x%llx",
12163a62b615Svisa 			    __func__, size, pa,
12173a62b615Svisa 			    pa_to_block(memdesc->head_addr)->size,
12183a62b615Svisa 			    memdesc->head_addr);
12193a62b615Svisa 		}
12203a62b615Svisa 		return;
12213a62b615Svisa 	}
12223a62b615Svisa 
12233a62b615Svisa 	/* Find the immediate predecessor. */
12243a62b615Svisa 	prevpa = memdesc->head_addr;
12253a62b615Svisa 	prev = pa_to_block(prevpa);
12263a62b615Svisa 	while (prev->next != 0 && prev->next < pa) {
12273a62b615Svisa 		prevpa = prev->next;
12283a62b615Svisa 		prev = pa_to_block(prevpa);
12293a62b615Svisa 	}
12303a62b615Svisa 	if (prevpa + prev->size > pa) {
12313a62b615Svisa 		panic("%s: overlap 2: 0x%llx @ 0x%lx / 0x%lx @ 0x%lx",
12323a62b615Svisa 		    __func__, prev->size, prevpa, size, pa);
12333a62b615Svisa 	}
12343a62b615Svisa 
12353a62b615Svisa 	/* Merge with or insert after the predecessor. */
12363a62b615Svisa 	if (prevpa + prev->size == pa) {
12373a62b615Svisa 		if (prev->next == 0) {
12383a62b615Svisa 			prev->size += size;
12393a62b615Svisa 			return;
12403a62b615Svisa 		}
12413a62b615Svisa 		next = pa_to_block(prev->next);
12423a62b615Svisa 		if (prevpa + prev->size + size < prev->next) {
12433a62b615Svisa 			prev->size += size;
12443a62b615Svisa 		} else if (prevpa + prev->size + size == prev->next) {
12453a62b615Svisa 			prev->next = next->next;
12463a62b615Svisa 			prev->size += size + next->size;
12473a62b615Svisa 		} else {
12483a62b615Svisa 			panic("%s: overlap 3: 0x%llx @ 0x%lx / 0x%lx @ 0x%lx / "
12493a62b615Svisa 			    "0x%llx @ 0x%llx", __func__,
12503a62b615Svisa 			    prev->size, prevpa, size, pa,
12513a62b615Svisa 			    next->size, prev->next);
12523a62b615Svisa 		}
12533a62b615Svisa 	} else {
12543a62b615Svisa 		/* The block is disjoint with prev. */
12553a62b615Svisa 		KASSERT(prevpa + prev->size < pa);
12563a62b615Svisa 
12573a62b615Svisa 		block = pa_to_block(pa);
12583a62b615Svisa 		if (pa + size < prev->next || prev->next == 0) {
12593a62b615Svisa 			block->next = prev->next;
12603a62b615Svisa 			block->size = size;
12613a62b615Svisa 			prev->next = pa;
12623a62b615Svisa 		} else if (pa + size == prev->next) {
12633a62b615Svisa 			next = pa_to_block(prev->next);
12643a62b615Svisa 			block->next = next->next;
12653a62b615Svisa 			block->size = next->size + size;
12663a62b615Svisa 			prev->next = pa;
12673a62b615Svisa 		} else {
12683a62b615Svisa 			next = pa_to_block(prev->next);
12693a62b615Svisa 			panic("%s: overlap 4: 0x%llx @ 0x%lx / "
12703a62b615Svisa 			    "0x%lx @ 0x%lx / 0x%llx @ 0x%llx",
12713a62b615Svisa 			    __func__, prev->size, prevpa, size, pa,
12723a62b615Svisa 			    next->size, prev->next);
12733a62b615Svisa 		}
12743a62b615Svisa 	}
12753a62b615Svisa }
12763a62b615Svisa #endif /* NOCTBOOT > 0 */
12773a62b615Svisa 
1278c6b2ceb4Ssyuu #ifdef MULTIPROCESSOR
1279fe411cd3Ssyuu uint32_t cpu_spinup_mask = 0;
1280fe411cd3Ssyuu uint64_t cpu_spinup_a0, cpu_spinup_sp;
1281718ef86bSsyuu 
1282c6b2ceb4Ssyuu void
hw_cpu_boot_secondary(struct cpu_info * ci)1283c6b2ceb4Ssyuu hw_cpu_boot_secondary(struct cpu_info *ci)
1284c6b2ceb4Ssyuu {
1285c6b2ceb4Ssyuu 	vaddr_t kstack;
1286c6b2ceb4Ssyuu 
1287c6b2ceb4Ssyuu 	kstack = alloc_contiguous_pages(USPACE);
1288a4a3b1beSjasper 	if (kstack == 0)
1289f6d8fcaeSderaadt 		panic("unable to allocate idle stack");
1290c6b2ceb4Ssyuu 	ci->ci_curprocpaddr = (void *)kstack;
129168be5be6Svisa 
1292fe411cd3Ssyuu 	cpu_spinup_a0 = (uint64_t)ci;
1293fe411cd3Ssyuu 	cpu_spinup_sp = (uint64_t)(kstack + USPACE);
129468be5be6Svisa 	mips_sync();
129568be5be6Svisa 
1296fe411cd3Ssyuu 	cpu_spinup_mask = (uint32_t)ci->ci_cpuid;
1297c6b2ceb4Ssyuu 
1298f016eb63Svisa 	while (!CPU_IS_RUNNING(ci))
1299f016eb63Svisa 		membar_sync();
1300c6b2ceb4Ssyuu }
1301c6b2ceb4Ssyuu 
1302c6b2ceb4Ssyuu void
hw_cpu_hatch(struct cpu_info * ci)1303c6b2ceb4Ssyuu hw_cpu_hatch(struct cpu_info *ci)
1304c6b2ceb4Ssyuu {
1305c6b2ceb4Ssyuu 	/*
1306c6b2ceb4Ssyuu 	 * Set curcpu address on this processor.
1307c6b2ceb4Ssyuu 	 */
1308c6b2ceb4Ssyuu 	setcurcpu(ci);
1309c6b2ceb4Ssyuu 
1310c6b2ceb4Ssyuu 	/*
1311c6b2ceb4Ssyuu 	 * Make sure we can access the extended address space.
1312c6b2ceb4Ssyuu 	 */
1313c6b2ceb4Ssyuu 	setsr(getsr() | SR_KX | SR_UX);
1314c6b2ceb4Ssyuu 
13158f99340cSvisa 	octeon_tlb_init();
1316c6b2ceb4Ssyuu 	tlb_set_pid(0);
1317c6b2ceb4Ssyuu 
1318c6b2ceb4Ssyuu 	/*
1319c6b2ceb4Ssyuu 	 * Turn off bootstrap exception vectors.
1320c6b2ceb4Ssyuu 	 */
1321c6b2ceb4Ssyuu 	setsr(getsr() & ~SR_BOOT_EXC_VEC);
1322c6b2ceb4Ssyuu 
1323c6b2ceb4Ssyuu 	/*
1324c6b2ceb4Ssyuu 	 * Clear out the I and D caches.
1325c6b2ceb4Ssyuu 	 */
1326c6b2ceb4Ssyuu 	Octeon_ConfigCache(ci);
1327c6b2ceb4Ssyuu 	Mips_SyncCache(ci);
1328c6b2ceb4Ssyuu 
1329185b3c79Smiod 	(*md_startclock)(ci);
1330f4728271Svisa 
133161e15267Ssyuu 	octeon_intr_init();
1332c6b2ceb4Ssyuu 	mips64_ipi_init();
1333f4728271Svisa 
13345c29d161Svisa 	ci->ci_flags |= CPUF_RUNNING;
13355c29d161Svisa 	membar_sync();
13365c29d161Svisa 
1337f4728271Svisa 	ncpus++;
1338f4728271Svisa 
1339c6b2ceb4Ssyuu 	spl0();
1340c6b2ceb4Ssyuu 	(void)updateimask(0);
1341c6b2ceb4Ssyuu 
1342*bb00e811Sclaudio 	sched_toidle();
1343c6b2ceb4Ssyuu }
13442c4f44bbSjasper #endif /* MULTIPROCESSOR */
1345