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