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