]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/mips/nlm/xlp_machdep.c
Upgrade Unbound to 1.7.1.
[FreeBSD/FreeBSD.git] / sys / mips / nlm / xlp_machdep.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright 2003-2011 Netlogic Microsystems (Netlogic). All rights
5  * reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are
9  * met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY Netlogic Microsystems ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28  * THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  * NETLOGIC_BSD */
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34
35 #include "opt_ddb.h"
36 #include "opt_platform.h"
37
38 #include <sys/param.h>
39 #include <sys/bus.h>
40 #include <sys/conf.h>
41 #include <sys/rtprio.h>
42 #include <sys/systm.h>
43 #include <sys/interrupt.h>
44 #include <sys/limits.h>
45 #include <sys/lock.h>
46 #include <sys/malloc.h>
47 #include <sys/mutex.h>
48 #include <sys/random.h>
49
50 #include <sys/cons.h>           /* cinit() */
51 #include <sys/kdb.h>
52 #include <sys/reboot.h>
53 #include <sys/queue.h>
54 #include <sys/smp.h>
55 #include <sys/timetc.h>
56
57 #include <vm/vm.h>
58 #include <vm/vm_page.h>
59
60 #include <machine/cpu.h>
61 #include <machine/cpufunc.h>
62 #include <machine/cpuinfo.h>
63 #include <machine/tlb.h>
64 #include <machine/cpuregs.h>
65 #include <machine/frame.h>
66 #include <machine/hwfunc.h>
67 #include <machine/md_var.h>
68 #include <machine/asm.h>
69 #include <machine/pmap.h>
70 #include <machine/trap.h>
71 #include <machine/clock.h>
72 #include <machine/fls64.h>
73 #include <machine/intr_machdep.h>
74 #include <machine/smp.h>
75
76 #include <mips/nlm/hal/mips-extns.h>
77 #include <mips/nlm/hal/haldefs.h>
78 #include <mips/nlm/hal/iomap.h>
79 #include <mips/nlm/hal/sys.h>
80 #include <mips/nlm/hal/pic.h>
81 #include <mips/nlm/hal/uart.h>
82 #include <mips/nlm/hal/mmu.h>
83 #include <mips/nlm/hal/bridge.h>
84 #include <mips/nlm/hal/cpucontrol.h>
85 #include <mips/nlm/hal/cop2.h>
86
87 #include <mips/nlm/clock.h>
88 #include <mips/nlm/interrupt.h>
89 #include <mips/nlm/board.h>
90 #include <mips/nlm/xlp.h>
91 #include <mips/nlm/msgring.h>
92
93 #ifdef FDT
94 #include <dev/fdt/fdt_common.h>
95 #include <dev/ofw/openfirm.h>
96 #endif
97
98 /* 4KB static data aread to keep a copy of the bootload env until
99    the dynamic kenv is setup */
100 char boot1_env[4096];
101
102 uint64_t xlp_cpu_frequency;
103 uint64_t xlp_io_base = MIPS_PHYS_TO_DIRECT_UNCACHED(XLP_DEFAULT_IO_BASE);
104
105 int xlp_ncores;
106 int xlp_threads_per_core;
107 uint32_t xlp_hw_thread_mask;
108 int xlp_cpuid_to_hwtid[MAXCPU];
109 int xlp_hwtid_to_cpuid[MAXCPU];
110 uint64_t xlp_pic_base;
111
112 static int xlp_mmuval;
113
114 extern uint32_t _end;
115 extern char XLPResetEntry[], XLPResetEntryEnd[];
116
117 static void
118 xlp_setup_core(void)
119 {
120         uint64_t reg;
121
122         reg = nlm_mfcr(LSU_DEFEATURE);
123         /* Enable Unaligned and L2HPE */
124         reg |= (1 << 30) | (1 << 23);
125         /*
126          * Experimental : Enable SUE
127          * Speculative Unmap Enable. Enable speculative L2 cache request for
128          * unmapped access.
129          */
130         reg |= (1ull << 31);
131         /* Clear S1RCM  - A0 errata */
132         reg &= ~0xeull;
133         nlm_mtcr(LSU_DEFEATURE, reg);
134
135         reg = nlm_mfcr(SCHED_DEFEATURE);
136         /* Experimental: Disable BRU accepting ALU ops - A0 errata */
137         reg |= (1 << 24);
138         nlm_mtcr(SCHED_DEFEATURE, reg);
139 }
140
141 static void
142 xlp_setup_mmu(void)
143 {
144         uint32_t pagegrain;
145
146         if (nlm_threadid() == 0) {
147                 nlm_setup_extended_pagemask(0);
148                 nlm_large_variable_tlb_en(1);
149                 nlm_extended_tlb_en(1);
150                 nlm_mmu_setup(0, 0, 0);
151         }
152
153         /* Enable no-read, no-exec, large-physical-address */
154         pagegrain = mips_rd_pagegrain();
155         pagegrain |= (1U << 31) |       /* RIE */
156             (1 << 30)           |       /* XIE */
157             (1 << 29);                  /* ELPA */
158         mips_wr_pagegrain(pagegrain);
159 }
160
161 static void
162 xlp_enable_blocks(void)
163 {
164         uint64_t sysbase;
165         int i;
166
167         for (i = 0; i < XLP_MAX_NODES; i++) {
168                 if (!nlm_dev_exists(XLP_IO_SYS_OFFSET(i)))
169                         continue;
170                 sysbase = nlm_get_sys_regbase(i);
171                 nlm_sys_enable_block(sysbase, DFS_DEVICE_RSA);
172         }
173 }
174
175 static void
176 xlp_parse_mmu_options(void)
177 {
178         uint64_t sysbase;
179         uint32_t cpu_map = xlp_hw_thread_mask;
180         uint32_t core0_thr_mask, core_thr_mask, cpu_rst_mask;
181         int i, j, k;
182
183 #ifdef SMP
184         if (cpu_map == 0)
185                 cpu_map = 0xffffffff;
186 #else /* Uniprocessor! */
187         if (cpu_map == 0)
188                 cpu_map = 0x1;
189         else if (cpu_map != 0x1) {
190                 printf("WARNING: Starting uniprocessor kernel on cpumask [0x%lx]!\n"
191                     "WARNING: Other CPUs will be unused.\n", (u_long)cpu_map);
192                 cpu_map = 0x1;
193         }
194 #endif
195
196         xlp_ncores = 1;
197         core0_thr_mask = cpu_map & 0xf;
198         switch (core0_thr_mask) {
199         case 1:
200                 xlp_threads_per_core = 1;
201                 xlp_mmuval = 0;
202                 break;
203         case 3:
204                 xlp_threads_per_core = 2;
205                 xlp_mmuval = 2;
206                 break;
207         case 0xf:
208                 xlp_threads_per_core = 4;
209                 xlp_mmuval = 3;
210                 break;
211         default:
212                 goto unsupp;
213         }
214
215         /* Try to find the enabled cores from SYS block */
216         sysbase = nlm_get_sys_regbase(0);
217         cpu_rst_mask = nlm_read_sys_reg(sysbase, SYS_CPU_RESET) & 0xff;
218
219         /* XLP 416 does not report this correctly, fix */
220         if (nlm_processor_id() == CHIP_PROCESSOR_ID_XLP_416)
221                 cpu_rst_mask = 0xe;
222
223         /* Take out cores which do not exist on chip */
224         for (i = 1; i < XLP_MAX_CORES; i++) {
225                 if ((cpu_rst_mask & (1 << i)) == 0)
226                         cpu_map &= ~(0xfu << (4 * i));
227         }
228
229         /* Verify other cores' CPU masks */
230         for (i = 1; i < XLP_MAX_CORES; i++) {
231                 core_thr_mask = (cpu_map >> (4 * i)) & 0xf;
232                 if (core_thr_mask == 0)
233                         continue;
234                 if (core_thr_mask != core0_thr_mask)
235                         goto unsupp;
236                 xlp_ncores++;
237         }
238
239         xlp_hw_thread_mask = cpu_map;
240         /* setup hardware processor id to cpu id mapping */
241         for (i = 0; i< MAXCPU; i++)
242                 xlp_cpuid_to_hwtid[i] =
243                     xlp_hwtid_to_cpuid[i] = -1;
244         for (i = 0, k = 0; i < XLP_MAX_CORES; i++) {
245                 if (((cpu_map >> (i * 4)) & 0xf) == 0)
246                         continue;
247                 for (j = 0; j < xlp_threads_per_core; j++) {
248                         xlp_cpuid_to_hwtid[k] = i * 4 + j;
249                         xlp_hwtid_to_cpuid[i * 4 + j] = k;
250                         k++;
251                 }
252         }
253
254         return;
255
256 unsupp:
257         printf("ERROR : Unsupported CPU mask [use 1,2 or 4 threads per core].\n"
258             "\tcore0 thread mask [%lx], boot cpu mask [%lx].\n",
259             (u_long)core0_thr_mask, (u_long)cpu_map);
260         panic("Invalid CPU mask - halting.\n");
261         return;
262 }
263
264 /* Parse cmd line args as env - copied from ar71xx */
265 static void
266 xlp_parse_bootargs(char *cmdline)
267 {
268         char *n, *v;
269
270         while ((v = strsep(&cmdline, " \n")) != NULL) {
271                 if (*v == '\0')
272                         continue;
273                 if (*v == '-') {
274                         while (*v != '\0') {
275                                 v++;
276                                 switch (*v) {
277                                 case 'a': boothowto |= RB_ASKNAME; break;
278                                 case 'd': boothowto |= RB_KDB; break;
279                                 case 'g': boothowto |= RB_GDB; break;
280                                 case 's': boothowto |= RB_SINGLE; break;
281                                 case 'v': boothowto |= RB_VERBOSE; break;
282                                 }
283                         }
284                 } else {
285                         n = strsep(&v, "=");
286                         if (v == NULL)
287                                 kern_setenv(n, "1");
288                         else
289                                 kern_setenv(n, v);
290                 }
291         }
292 }
293
294 #ifdef FDT
295 static void
296 xlp_bootargs_init(__register_t arg)
297 {
298         char    buf[2048]; /* early stack is big enough */
299         void    *dtbp;
300         phandle_t chosen;
301         ihandle_t mask;
302
303         dtbp = (void *)(intptr_t)arg;
304 #if defined(FDT_DTB_STATIC)
305         /*
306          * In case the device tree blob was not passed as argument try
307          * to use the statically embedded one.
308          */
309         if (dtbp == NULL)
310                 dtbp = &fdt_static_dtb;
311 #endif
312         if (OF_install(OFW_FDT, 0) == FALSE)
313                 while (1);
314         if (OF_init((void *)dtbp) != 0)
315                 while (1);
316         OF_interpret("perform-fixup", 0);
317
318         chosen = OF_finddevice("/chosen");
319         if (OF_getprop(chosen, "cpumask", &mask, sizeof(mask)) != -1) {
320                 xlp_hw_thread_mask = mask;
321         }
322
323         if (OF_getprop(chosen, "bootargs", buf, sizeof(buf)) != -1)
324                 xlp_parse_bootargs(buf);
325 }
326 #else
327 /*
328  * arg is a pointer to the environment block, the format of the block is
329  * a=xyz\0b=pqr\0\0
330  */
331 static void
332 xlp_bootargs_init(__register_t arg)
333 {
334         char    buf[2048]; /* early stack is big enough */
335         char    *p, *v, *n;
336         uint32_t mask;
337
338         /*
339          * provide backward compat for passing cpu mask as arg
340          */
341         if (arg & 1) {
342                 xlp_hw_thread_mask = arg;
343                 return;
344         }
345
346         p = (void *)(intptr_t)arg;
347         while (*p != '\0') {
348                 strlcpy(buf, p, sizeof(buf));
349                 v = buf;
350                 n = strsep(&v, "=");
351                 if (v == NULL)
352                         kern_setenv(n, "1");
353                 else
354                         kern_setenv(n, v);
355                 p += strlen(p) + 1;
356         }
357
358         /* CPU mask can be passed thru env */
359         if (getenv_uint("cpumask", &mask) != 0)
360                 xlp_hw_thread_mask = mask;
361
362         /* command line argument */
363         v = kern_getenv("bootargs");
364         if (v != NULL) {
365                 strlcpy(buf, v, sizeof(buf));
366                 xlp_parse_bootargs(buf);
367                 freeenv(v);
368         }
369 }
370 #endif
371
372 static void
373 mips_init(void)
374 {
375         init_param1();
376         init_param2(physmem);
377
378         mips_cpu_init();
379         cpuinfo.cache_coherent_dma = TRUE;
380         pmap_bootstrap();
381         mips_proc0_init();
382         mutex_init();
383 #ifdef DDB
384         kdb_init();
385         if (boothowto & RB_KDB) {
386                 kdb_enter("Boot flags requested debugger", NULL);
387         }
388 #endif
389 }
390
391 unsigned int
392 platform_get_timecount(struct timecounter *tc __unused)
393 {
394         uint64_t count = nlm_pic_read_timer(xlp_pic_base, PIC_CLOCK_TIMER);
395
396         return (unsigned int)~count;
397 }
398
399 static void
400 xlp_pic_init(void)
401 {
402         struct timecounter pic_timecounter = {
403                 platform_get_timecount, /* get_timecount */
404                 0,                      /* no poll_pps */
405                 ~0U,                    /* counter_mask */
406                 XLP_IO_CLK,            /* frequency */
407                 "XLRPIC",               /* name */
408                 2000,                   /* quality (adjusted in code) */
409         };
410         int i;
411         int maxirt;
412
413         xlp_pic_base = nlm_get_pic_regbase(0);  /* TOOD: Add other nodes */
414         maxirt = nlm_read_reg(nlm_get_pic_pcibase(nlm_nodeid()),
415             XLP_PCI_DEVINFO_REG0);
416         printf("Initializing PIC...@%jx %d IRTs\n", (uintmax_t)xlp_pic_base,
417             maxirt);
418         /* Bind all PIC irqs to cpu 0 */
419         for (i = 0; i < maxirt; i++)
420             nlm_pic_write_irt(xlp_pic_base, i, 0, 0, 1, 0,
421             1, 0, 0x1);
422
423         nlm_pic_set_timer(xlp_pic_base, PIC_CLOCK_TIMER, ~0ULL, 0, 0);
424         platform_timecounter = &pic_timecounter;
425 }
426
427 #if defined(__mips_n32) || defined(__mips_n64) /* PHYSADDR_64_BIT */
428 #ifdef XLP_SIM
429 #define XLP_MEM_LIM     0x200000000ULL
430 #else
431 #define XLP_MEM_LIM     0x10000000000ULL
432 #endif
433 #else
434 #define XLP_MEM_LIM     0xfffff000UL
435 #endif
436 static vm_paddr_t xlp_mem_excl[] = {
437         0,          0,          /* for kernel image region, see xlp_mem_init */
438         0x0c000000, 0x14000000, /* uboot area, cms queue and other stuff */
439         0x1fc00000, 0x1fd00000, /* reset vec */
440         0x1e000000, 0x1e200000, /* poe buffers */
441 };
442
443 static int
444 mem_exclude_add(vm_paddr_t *avail, vm_paddr_t mstart, vm_paddr_t mend)
445 {
446         int i, pos;
447
448         pos = 0;
449         for (i = 0; i < nitems(xlp_mem_excl); i += 2) {
450                 if (mstart > xlp_mem_excl[i + 1])
451                         continue;
452                 if (mstart < xlp_mem_excl[i]) {
453                         avail[pos++] = mstart;
454                         if (mend < xlp_mem_excl[i])
455                                 avail[pos++] = mend;
456                         else
457                                 avail[pos++] = xlp_mem_excl[i];
458                 }
459                 mstart = xlp_mem_excl[i + 1];
460                 if (mend <= mstart)
461                         break;
462         }
463         if (mstart < mend) {
464                 avail[pos++] = mstart;
465                 avail[pos++] = mend;
466         }
467         return (pos);
468 }
469
470 static void
471 xlp_mem_init(void)
472 {
473         vm_paddr_t physsz, tmp;
474         uint64_t bridgebase, base, lim, val;
475         int i, j, k, n;
476
477         /* update kernel image area in exclude regions */
478         tmp = (vm_paddr_t)MIPS_KSEG0_TO_PHYS(&_end);
479         tmp = round_page(tmp) + 0x20000; /* round up */
480         xlp_mem_excl[1] = tmp;
481
482         printf("Memory (from DRAM BARs):\n");
483         bridgebase = nlm_get_bridge_regbase(0); /* TODO: Add other nodes */
484         physsz = 0;
485         for (i = 0, j = 0; i < 8; i++) {
486                 val = nlm_read_bridge_reg(bridgebase, BRIDGE_DRAM_BAR(i));
487                 val = (val >>  12) & 0xfffff;
488                 base = val << 20;
489                 val = nlm_read_bridge_reg(bridgebase, BRIDGE_DRAM_LIMIT(i));
490                 val = (val >>  12) & 0xfffff;
491                 if (val == 0)   /* BAR not enabled */
492                         continue;
493                 lim = (val + 1) << 20;
494                 printf("  BAR %d: %#jx - %#jx : ", i, (intmax_t)base,
495                     (intmax_t)lim);
496
497                 if (lim <= base) {
498                         printf("\tskipped - malformed %#jx -> %#jx\n",
499                             (intmax_t)base, (intmax_t)lim);
500                         continue;
501                 } else if (base >= XLP_MEM_LIM) {
502                         printf(" skipped - outside usable limit %#jx.\n",
503                             (intmax_t)XLP_MEM_LIM);
504                         continue;
505                 } else if (lim >= XLP_MEM_LIM) {
506                         lim = XLP_MEM_LIM;
507                         printf(" truncated to %#jx.\n", (intmax_t)XLP_MEM_LIM);
508                 } else
509                         printf(" usable\n");
510
511                 /* exclude unusable regions from BAR and add rest */
512                 n = mem_exclude_add(&phys_avail[j], base, lim);
513                 for (k = j; k < j + n; k += 2) {
514                         physsz += phys_avail[k + 1] - phys_avail[k];
515                         printf("\tMem[%d]: %#jx - %#jx\n", k/2,
516                             (intmax_t)phys_avail[k], (intmax_t)phys_avail[k+1]);
517                 }
518                 j = k;
519         }
520
521         /* setup final entry with 0 */
522         phys_avail[j] = phys_avail[j + 1] = 0;
523
524         /* copy phys_avail to dump_avail */
525         for (i = 0; i <= j + 1; i++)
526                 dump_avail[i] = phys_avail[i];
527
528         realmem = physmem = btoc(physsz);
529 }
530
531 void
532 platform_start(__register_t a0 __unused,
533     __register_t a1 __unused,
534     __register_t a2 __unused,
535     __register_t a3 __unused)
536 {
537
538         /* Initialize pcpu stuff */
539         mips_pcpu0_init();
540
541         /* initialize console so that we have printf */
542         boothowto |= (RB_SERIAL | RB_MULTIPLE); /* Use multiple consoles */
543
544         init_static_kenv(boot1_env, sizeof(boot1_env));
545         xlp_bootargs_init(a0);
546
547         /* clockrate used by delay, so initialize it here */
548         xlp_cpu_frequency = xlp_get_cpu_frequency(0, 0);
549         cpu_clock = xlp_cpu_frequency / 1000000;
550         mips_timer_early_init(xlp_cpu_frequency);
551
552         /* Init console please */
553         cninit();
554
555         /* Early core init and fixes for errata */
556         xlp_setup_core();
557
558         xlp_parse_mmu_options();
559         xlp_mem_init();
560
561         bcopy(XLPResetEntry, (void *)MIPS_RESET_EXC_VEC,
562               XLPResetEntryEnd - XLPResetEntry);
563 #ifdef SMP
564         /*
565          * We will enable the other threads in core 0 here
566          * so that the TLB and cache info is correct when
567          * mips_init runs
568          */
569         xlp_enable_threads(xlp_mmuval);
570 #endif
571         /* setup for the startup core */
572         xlp_setup_mmu();
573
574         xlp_enable_blocks();
575
576         /* Read/Guess/setup board information */
577         nlm_board_info_setup();
578
579         /* MIPS generic init */
580         mips_init();
581
582         /*
583          * XLP specific post initialization
584          * initialize other on chip stuff
585          */
586         xlp_pic_init();
587
588         mips_timer_init_params(xlp_cpu_frequency, 0);
589 }
590
591 void
592 platform_cpu_init()
593 {
594 }
595
596 void
597 platform_reset(void)
598 {
599         uint64_t sysbase = nlm_get_sys_regbase(0);
600
601         nlm_write_sys_reg(sysbase, SYS_CHIP_RESET, 1);
602         for( ; ; )
603                 __asm __volatile("wait");
604 }
605
606 #ifdef SMP
607 /*
608  * XLP threads are started simultaneously when we enable threads, this will
609  * ensure that the threads are blocked in platform_init_ap, until they are
610  * ready to proceed to smp_init_secondary()
611  */
612 static volatile int thr_unblock[4];
613
614 int
615 platform_start_ap(int cpuid)
616 {
617         uint32_t coremask, val;
618         uint64_t sysbase = nlm_get_sys_regbase(0);
619         int hwtid = xlp_cpuid_to_hwtid[cpuid];
620         int core, thr;
621
622         core = hwtid / 4;
623         thr = hwtid % 4;
624         if (thr == 0) {
625                 /* First thread in core, do core wake up */
626                 coremask = 1u << core;
627
628                 /* Enable core clock */
629                 val = nlm_read_sys_reg(sysbase, SYS_CORE_DFS_DIS_CTRL);
630                 val &= ~coremask;
631                 nlm_write_sys_reg(sysbase, SYS_CORE_DFS_DIS_CTRL, val);
632
633                 /* Remove CPU Reset */
634                 val = nlm_read_sys_reg(sysbase, SYS_CPU_RESET);
635                 val &=  ~coremask & 0xff;
636                 nlm_write_sys_reg(sysbase, SYS_CPU_RESET, val);
637
638                 if (bootverbose)
639                         printf("Waking up core %d ...", core);
640
641                 /* Poll for CPU to mark itself coherent */
642                 do {
643                         val = nlm_read_sys_reg(sysbase, SYS_CPU_NONCOHERENT_MODE);
644                 } while ((val & coremask) != 0);
645                 if (bootverbose)
646                         printf("Done\n");
647         } else {
648                 /* otherwise release the threads stuck in platform_init_ap */
649                 thr_unblock[thr] = 1;
650         }
651
652         return (0);
653 }
654
655 void
656 platform_init_ap(int cpuid)
657 {
658         uint32_t stat;
659         int thr;
660
661         /* The first thread has to setup the MMU and enable other threads */
662         thr = nlm_threadid();
663         if (thr == 0) {
664                 xlp_setup_core();
665                 xlp_enable_threads(xlp_mmuval);
666         } else {
667                 /*
668                  * FIXME busy wait here eats too many cycles, especially
669                  * in the core 0 while bootup
670                  */
671                 while (thr_unblock[thr] == 0)
672                         __asm__ __volatile__ ("nop;nop;nop;nop");
673                 thr_unblock[thr] = 0;
674         }
675
676         xlp_setup_mmu();
677         stat = mips_rd_status();
678         KASSERT((stat & MIPS_SR_INT_IE) == 0,
679             ("Interrupts enabled in %s!", __func__));
680         stat |= MIPS_SR_COP_2_BIT | MIPS_SR_COP_0_BIT;
681         mips_wr_status(stat);
682
683         nlm_write_c0_eimr(0ull);
684         xlp_enable_irq(IRQ_IPI);
685         xlp_enable_irq(IRQ_TIMER);
686         xlp_enable_irq(IRQ_MSGRING);
687
688         return;
689 }
690
691 int
692 platform_ipi_hardintr_num(void)
693 {
694
695         return (IRQ_IPI);
696 }
697
698 int
699 platform_ipi_softintr_num(void)
700 {
701
702         return (-1);
703 }
704
705 void
706 platform_ipi_send(int cpuid)
707 {
708
709         nlm_pic_send_ipi(xlp_pic_base, xlp_cpuid_to_hwtid[cpuid],
710             platform_ipi_hardintr_num(), 0);
711 }
712
713 void
714 platform_ipi_clear(void)
715 {
716 }
717
718 int
719 platform_processor_id(void)
720 {
721
722         return (xlp_hwtid_to_cpuid[nlm_cpuid()]);
723 }
724
725 void
726 platform_cpu_mask(cpuset_t *mask)
727 {
728         int i, s;
729
730         CPU_ZERO(mask);
731         s = xlp_ncores * xlp_threads_per_core;
732         for (i = 0; i < s; i++)
733                 CPU_SET(i, mask);
734 }
735
736 struct cpu_group *
737 platform_smp_topo()
738 {
739
740         return (smp_topo_2level(CG_SHARE_L2, xlp_ncores, CG_SHARE_L1,
741                 xlp_threads_per_core, CG_FLAG_THREAD));
742 }
743 #endif