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