xref: /illumos-gate/usr/src/uts/sun4v/cpu/niagara.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include <sys/systm.h>
31 #include <sys/archsystm.h>
32 #include <sys/machparam.h>
33 #include <sys/machsystm.h>
34 #include <sys/cpu.h>
35 #include <sys/elf_SPARC.h>
36 #include <vm/hat_sfmmu.h>
37 #include <vm/page.h>
38 #include <sys/cpuvar.h>
39 #include <sys/async.h>
40 #include <sys/cmn_err.h>
41 #include <sys/debug.h>
42 #include <sys/dditypes.h>
43 #include <sys/sunddi.h>
44 #include <sys/cpu_module.h>
45 #include <sys/prom_debug.h>
46 #include <sys/vmsystm.h>
47 #include <sys/prom_plat.h>
48 #include <sys/sysmacros.h>
49 #include <sys/intreg.h>
50 #include <sys/machtrap.h>
51 #include <sys/ontrap.h>
52 #include <sys/ivintr.h>
53 #include <sys/atomic.h>
54 #include <sys/panic.h>
55 #include <sys/dtrace.h>
56 #include <sys/simulate.h>
57 #include <sys/fault.h>
58 
59 #define	S_VAC_SIZE	MMU_PAGESIZE /* XXXQ? */
60 
61 /*
62  * Maximum number of contexts
63  */
64 #define	MAX_NCTXS	(1 << 13)
65 
66 uint_t root_phys_addr_lo_mask = 0xffffffffU;
67 
68 #ifdef NIAGARA_ERRATUM_39
69 extern int	niagara_erratum_39;
70 static uint64_t	cpu_ver;			/* Niagara CPU version reg */
71 
72 /* Niagara CPU version register */
73 #define	VER_MASK_MAJOR_SHIFT	28
74 #define	VER_MASK_MAJOR_MASK	0xf
75 
76 extern uint64_t	va_to_pa(void *);
77 extern uint64_t	ni_getver();			/* HV code to get %hver */
78 extern uint64_t	niagara_getver(uint64_t ni_getver_ra, uint64_t *cpu_version);
79 
80 #endif	/* NIAGARA_ERRATUM_39 */
81 
82 void
83 cpu_setup(void)
84 {
85 	extern int at_flags;
86 	extern int disable_delay_tlb_flush, delay_tlb_flush;
87 	extern int mmu_exported_pagesize_mask;
88 	extern int get_cpu_pagesizes(void);
89 	extern int cpc_has_overflow_intr;
90 
91 #ifdef NIAGARA_ERRATUM_39
92 	/*
93 	 * Get CPU version and enable Niagara erratum 39 workaround only
94 	 * on Niagara 1.x part. This workaround can also be enabled via
95 	 * /etc/system.
96 	 */
97 	if (niagara_getver(va_to_pa((void *)ni_getver), &cpu_ver) == H_EOK &&
98 	    ((cpu_ver >> VER_MASK_MAJOR_SHIFT) & VER_MASK_MAJOR_MASK) <= 1)
99 		niagara_erratum_39 = 1;
100 #endif
101 	cache |= (CACHE_PTAG | CACHE_IOCOHERENT);
102 
103 	/* XXXQ */
104 	at_flags = EF_SPARC_SUN_US3 | EF_SPARC_32PLUS | EF_SPARC_SUN_US1;
105 
106 	/*
107 	 * Use the maximum number of contexts available for Spitfire unless
108 	 * it has been tuned for debugging.
109 	 * We are checking against 0 here since this value can be patched
110 	 * while booting.  It can not be patched via /etc/system since it
111 	 * will be patched too late and thus cause the system to panic.
112 	 */
113 	if (nctxs == 0)
114 		nctxs = MAX_NCTXS;
115 
116 	if (use_page_coloring) {
117 		do_pg_coloring = 1;
118 		if (use_virtual_coloring)
119 			do_virtual_coloring = 1;
120 	}
121 	/*
122 	 * Initalize supported page sizes information before the PD.
123 	 * If no information is available, then initialize the
124 	 * mmu_exported_pagesize_mask to a reasonable value for that processor.
125 	 */
126 	mmu_exported_pagesize_mask = get_cpu_pagesizes();
127 	if (mmu_exported_pagesize_mask <= 0) {
128 		mmu_exported_pagesize_mask = (1 << TTE8K) | (1 << TTE64K) |
129 		    (1 << TTE4M) | (1 << TTE256M);
130 	}
131 
132 	/*
133 	 * Tune pp_slots to use up to 1/8th of the tlb entries.
134 	 */
135 	pp_slots = MIN(8, MAXPP_SLOTS);
136 
137 	/*
138 	 * Block stores invalidate all pages of the d$ so pagecopy
139 	 * et. al. do not need virtual translations with virtual
140 	 * coloring taken into consideration.
141 	 */
142 	pp_consistent_coloring = 0;
143 	isa_list =
144 	    "sparcv9 sparcv8plus sparcv8 sparcv8-fsmuld sparcv7 "
145 	    "sparc sparcv9+vis sparcv9+vis2 sparcv8plus+vis sparcv8plus+vis2";
146 
147 	cpu_hwcap_flags |= AV_SPARC_ASI_BLK_INIT;
148 
149 	/*
150 	 * On Spitfire, there's a hole in the address space
151 	 * that we must never map (the hardware only support 44-bits of
152 	 * virtual address).  Later CPUs are expected to have wider
153 	 * supported address ranges.
154 	 *
155 	 * See address map on p23 of the UltraSPARC 1 user's manual.
156 	 */
157 /* XXXQ get from machine description */
158 	hole_start = (caddr_t)0x80000000000ull;
159 	hole_end = (caddr_t)0xfffff80000000000ull;
160 
161 	/*
162 	 * The kpm mapping window.
163 	 * kpm_size:
164 	 *	The size of a single kpm range.
165 	 *	The overall size will be: kpm_size * vac_colors.
166 	 * kpm_vbase:
167 	 *	The virtual start address of the kpm range within the kernel
168 	 *	virtual address space. kpm_vbase has to be kpm_size aligned.
169 	 */
170 	kpm_size = (size_t)(2ull * 1024 * 1024 * 1024 * 1024); /* 2TB */
171 	kpm_size_shift = 41;
172 	kpm_vbase = (caddr_t)0xfffffa0000000000ull; /* 16EB - 6TB */
173 
174 	/*
175 	 * The traptrace code uses either %tick or %stick for
176 	 * timestamping.  We have %stick so we can use it.
177 	 */
178 	traptrace_use_stick = 1;
179 
180 	/*
181 	 * sun4v provides demap_all
182 	 */
183 	if (!disable_delay_tlb_flush)
184 		delay_tlb_flush = 1;
185 	/*
186 	 * Niagara has a performance counter overflow interrupt
187 	 */
188 	cpc_has_overflow_intr = 1;
189 }
190 
191 #define	MB	 * 1024 * 1024
192 /*
193  * Set the magic constants of the implementation.
194  */
195 void
196 cpu_fiximp(struct cpu_node *cpunode)
197 {
198 	extern int vac_size, vac_shift;
199 	extern uint_t vac_mask;
200 	int i, a;
201 
202 	/*
203 	 * The assumption here is that fillsysinfo will eventually
204 	 * have code to fill this info in from the PD.
205 	 * We hard code this for niagara now.
206 	 * Once the PD access library is done this code
207 	 * might need to be changed to get the info from the PD
208 	 */
209 	if (cpunode->ecache_size == 0)
210 		cpunode->ecache_size = 3 MB;
211 	if (cpunode->ecache_linesize == 0)
212 		cpunode->ecache_linesize = 64;
213 	if (cpunode->ecache_associativity == 0)
214 		cpunode->ecache_associativity = 12;
215 
216 	cpunode->ecache_setsize =
217 	    cpunode->ecache_size / cpunode->ecache_associativity;
218 
219 	if (ecache_setsize == 0)
220 		ecache_setsize = cpunode->ecache_setsize;
221 	if (ecache_alignsize == 0)
222 		ecache_alignsize = cpunode->ecache_linesize;
223 
224 	vac_size = S_VAC_SIZE;
225 	vac_mask = MMU_PAGEMASK & (vac_size - 1);
226 	i = 0; a = vac_size;
227 	while (a >>= 1)
228 		++i;
229 	vac_shift = i;
230 	shm_alignment = vac_size;
231 	vac = 0;
232 }
233 
234 static int niagara_cpucnt;
235 
236 void
237 cpu_init_private(struct cpu *cp)
238 {
239 	extern int niagara_kstat_init(void);
240 
241 	ASSERT(MUTEX_HELD(&cpu_lock));
242 	if (niagara_cpucnt++ == 0) {
243 		(void) niagara_kstat_init();
244 	}
245 }
246 
247 void
248 cpu_uninit_private(struct cpu *cp)
249 {
250 	extern int niagara_kstat_fini(void);
251 
252 	ASSERT(MUTEX_HELD(&cpu_lock));
253 	if (--niagara_cpucnt == 0) {
254 		(void) niagara_kstat_fini();
255 	}
256 }
257 
258 /*
259  * On Niagara, any flush will cause all preceding stores to be
260  * synchronized wrt the i$, regardless of address or ASI.  In fact,
261  * the address is ignored, so we always flush address 0.
262  */
263 void
264 dtrace_flush_sec(uintptr_t addr)
265 {
266 	doflush(0);
267 }
268 
269 #define	IS_FLOAT(i) (((i) & 0x1000000) != 0)
270 #define	IS_IBIT_SET(x)	(x & 0x2000)
271 #define	IS_VIS1(op, op3)(op == 2 && op3 == 0x36)
272 #define	IS_PARTIAL_OR_SHORT_FLOAT_LD_ST(op, op3, asi)		\
273 		(op == 3 && (op3 == IOP_V8_LDDFA ||		\
274 		op3 == IOP_V8_STDFA) &&	asi > ASI_SNFL)
275 int
276 vis1_partial_support(struct regs *rp, k_siginfo_t *siginfo, uint_t *fault)
277 {
278 	char *badaddr;
279 	int instr;
280 	uint_t	optype, op3, asi;
281 	uint_t	rd, ignor;
282 
283 	ASSERT(USERMODE(rp->r_tstate));
284 
285 	instr = fetch_user_instr((caddr_t)rp->r_pc);
286 
287 	rd = (instr >> 25) & 0x1f;
288 	optype = (instr >> 30) & 0x3;
289 	op3 = (instr >> 19) & 0x3f;
290 	ignor = (instr >> 5) & 0xff;
291 	if (IS_IBIT_SET(instr)) {
292 		asi = (uint32_t)((rp->r_tstate >> TSTATE_ASI_SHIFT) &
293 		    TSTATE_ASI_MASK);
294 	} else {
295 		asi = ignor;
296 	}
297 
298 	if (!IS_VIS1(optype, op3) &&
299 	    !IS_PARTIAL_OR_SHORT_FLOAT_LD_ST(optype, op3, asi)) {
300 		return (-1);
301 	}
302 	switch (simulate_unimp(rp, &badaddr)) {
303 	case SIMU_RETRY:
304 		break;	/* regs are already set up */
305 		/*NOTREACHED*/
306 
307 	case SIMU_SUCCESS:
308 		/*
309 		 * skip the successfully
310 		 * simulated instruction
311 		 */
312 		rp->r_pc = rp->r_npc;
313 		rp->r_npc += 4;
314 		break;
315 		/*NOTREACHED*/
316 
317 	case SIMU_FAULT:
318 		siginfo->si_signo = SIGSEGV;
319 		siginfo->si_code = SEGV_MAPERR;
320 		siginfo->si_addr = badaddr;
321 		*fault = FLTBOUNDS;
322 		break;
323 
324 	case SIMU_DZERO:
325 		siginfo->si_signo = SIGFPE;
326 		siginfo->si_code = FPE_INTDIV;
327 		siginfo->si_addr = (caddr_t)rp->r_pc;
328 		*fault = FLTIZDIV;
329 		break;
330 
331 	case SIMU_UNALIGN:
332 		siginfo->si_signo = SIGBUS;
333 		siginfo->si_code = BUS_ADRALN;
334 		siginfo->si_addr = badaddr;
335 		*fault = FLTACCESS;
336 		break;
337 
338 	case SIMU_ILLEGAL:
339 	default:
340 		siginfo->si_signo = SIGILL;
341 		op3 = (instr >> 19) & 0x3F;
342 		if ((IS_FLOAT(instr) && (op3 == IOP_V8_STQFA) ||
343 		    (op3 == IOP_V8_STDFA)))
344 			siginfo->si_code = ILL_ILLADR;
345 		else
346 			siginfo->si_code = ILL_ILLOPC;
347 		siginfo->si_addr = (caddr_t)rp->r_pc;
348 		*fault = FLTILL;
349 		break;
350 	}
351 	return (0);
352 }
353