xref: /illumos-gate/usr/src/uts/sun4u/os/mach_startup.c (revision c56c1e58d46678af913f4c68f2ef9dcacb5f282f)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <sys/machsystm.h>
29 #include <sys/archsystm.h>
30 #include <sys/vm.h>
31 #include <sys/cpu.h>
32 #include <sys/atomic.h>
33 #include <sys/reboot.h>
34 #include <sys/kdi.h>
35 #include <sys/bootconf.h>
36 #include <sys/memlist_plat.h>
37 #include <sys/memlist_impl.h>
38 #include <sys/prom_plat.h>
39 #include <sys/prom_isa.h>
40 #include <sys/autoconf.h>
41 #include <sys/intreg.h>
42 #include <sys/ivintr.h>
43 #include <sys/fpu/fpusystm.h>
44 #include <sys/iommutsb.h>
45 #include <vm/vm_dep.h>
46 #include <vm/seg_kmem.h>
47 #include <vm/seg_kpm.h>
48 #include <vm/seg_map.h>
49 #include <vm/seg_kp.h>
50 #include <sys/sysconf.h>
51 #include <vm/hat_sfmmu.h>
52 #include <sys/kobj.h>
53 #include <sys/sun4asi.h>
54 #include <sys/clconf.h>
55 #include <sys/platform_module.h>
56 #include <sys/panic.h>
57 #include <sys/cpu_sgnblk_defs.h>
58 #include <sys/clock.h>
59 #include <sys/fpras_impl.h>
60 #include <sys/prom_debug.h>
61 #include <sys/traptrace.h>
62 #include <sys/memnode.h>
63 #include <sys/mem_cage.h>
64 
65 /*
66  * fpRAS implementation structures.
67  */
68 struct fpras_chkfn *fpras_chkfnaddrs[FPRAS_NCOPYOPS];
69 struct fpras_chkfngrp *fpras_chkfngrps;
70 struct fpras_chkfngrp *fpras_chkfngrps_base;
71 int fpras_frequency = -1;
72 int64_t fpras_interval = -1;
73 
74 void
75 setup_trap_table(void)
76 {
77 	intr_init(CPU);			/* init interrupt request free list */
78 	setwstate(WSTATE_KERN);
79 	prom_set_traptable(&trap_table);
80 }
81 
82 void
83 mach_fpras()
84 {
85 	if (fpras_implemented && !fpras_disable) {
86 		int i;
87 		struct fpras_chkfngrp *fcgp;
88 		size_t chkfngrpsallocsz;
89 
90 		/*
91 		 * Note that we size off of NCPU and setup for
92 		 * all those possibilities regardless of whether
93 		 * the cpu id is present or not.  We do this so that
94 		 * we don't have any construction or destruction
95 		 * activity to perform at DR time, and it's not
96 		 * costly in memory.  We require block alignment.
97 		 */
98 		chkfngrpsallocsz = NCPU * sizeof (struct fpras_chkfngrp);
99 		fpras_chkfngrps_base = kmem_alloc(chkfngrpsallocsz, KM_SLEEP);
100 		if (IS_P2ALIGNED((uintptr_t)fpras_chkfngrps_base, 64)) {
101 			fpras_chkfngrps = fpras_chkfngrps_base;
102 		} else {
103 			kmem_free(fpras_chkfngrps_base, chkfngrpsallocsz);
104 			chkfngrpsallocsz += 64;
105 			fpras_chkfngrps_base = kmem_alloc(chkfngrpsallocsz,
106 			    KM_SLEEP);
107 			fpras_chkfngrps = (struct fpras_chkfngrp *)
108 			    P2ROUNDUP((uintptr_t)fpras_chkfngrps_base, 64);
109 		}
110 
111 		/*
112 		 * Copy our check function into place for each copy operation
113 		 * and each cpu id.
114 		 */
115 		fcgp = &fpras_chkfngrps[0];
116 		for (i = 0; i < FPRAS_NCOPYOPS; ++i)
117 			bcopy((void *)fpras_chkfn_type1, &fcgp->fpras_fn[i],
118 			    sizeof (struct fpras_chkfn));
119 		for (i = 1; i < NCPU; ++i)
120 			*(&fpras_chkfngrps[i]) = *fcgp;
121 
122 		/*
123 		 * At definition fpras_frequency is set to -1, and it will
124 		 * still have that value unless changed in /etc/system (not
125 		 * strictly supported, but not preventable).  The following
126 		 * both sets the default and sanity checks anything from
127 		 * /etc/system.
128 		 */
129 		if (fpras_frequency < 0)
130 			fpras_frequency = FPRAS_DEFAULT_FREQUENCY;
131 
132 		/*
133 		 * Now calculate fpras_interval.  When fpras_interval
134 		 * becomes non-negative fpras checks will commence
135 		 * (copies before this point in boot will bypass fpras).
136 		 * Our stores of instructions must be visible; no need
137 		 * to flush as they're never been executed before.
138 		 */
139 		membar_producer();
140 		fpras_interval = (fpras_frequency == 0) ?
141 		    0 : sys_tick_freq / fpras_frequency;
142 	}
143 }
144 
145 void
146 mach_hw_copy_limit(void)
147 {
148 	if (!fpu_exists) {
149 		use_hw_bcopy = 0;
150 		hw_copy_limit_1 = 0;
151 		hw_copy_limit_2 = 0;
152 		hw_copy_limit_4 = 0;
153 		hw_copy_limit_8 = 0;
154 		use_hw_bzero = 0;
155 	}
156 }
157 
158 void
159 load_tod_module()
160 {
161 	/*
162 	 * Load tod driver module for the tod part found on this system.
163 	 * Recompute the cpu frequency/delays based on tod as tod part
164 	 * tends to keep time more accurately.
165 	 */
166 	if (tod_module_name == NULL || modload("tod", tod_module_name) == -1)
167 		halt("Can't load tod module");
168 }
169 
170 void
171 mach_memscrub(void)
172 {
173 	/*
174 	 * Startup memory scrubber, if not running fpu emulation code.
175 	 */
176 
177 	if (fpu_exists) {
178 		if (memscrub_init()) {
179 			cmn_err(CE_WARN,
180 			    "Memory scrubber failed to initialize");
181 		}
182 	}
183 }
184 
185 void
186 mach_cpu_halt_idle()
187 {
188 	/* no suport for halting idle CPU */
189 }
190 
191 /*ARGSUSED*/
192 void
193 cpu_intrq_setup(struct cpu *cp)
194 {
195 	/* Interrupt mondo queues not applicable to sun4u */
196 }
197 
198 /*ARGSUSED*/
199 void
200 cpu_intrq_register(struct cpu *cp)
201 {
202 	/* Interrupt/error queues not applicable to sun4u */
203 }
204 
205 /*ARGSUSED*/
206 void
207 mach_htraptrace_setup(int cpuid)
208 {
209 	/* Setup hypervisor traptrace buffer, not applicable to sun4u */
210 }
211 
212 /*ARGSUSED*/
213 void
214 mach_htraptrace_configure(int cpuid)
215 {
216 	/* enable/ disable hypervisor traptracing, not applicable to sun4u */
217 }
218 
219 /*ARGSUSED*/
220 void
221 mach_htraptrace_init(void)
222 {
223 	/* allocate hypervisor traptrace buffer, not applicable to sun4u */
224 }
225 
226 /*ARGSUSED*/
227 void
228 mach_htraptrace_cleanup(int cpuid)
229 {
230 	/* cleanup hypervisor traptrace buffer, not applicable to sun4u */
231 }
232 
233 void
234 mach_descrip_init(void)
235 {
236 	/* Obtain Machine description - only for sun4v */
237 }
238 
239 void
240 hsvc_setup(void)
241 {
242 	/* Setup hypervisor services, not applicable to sun4u */
243 }
244 
245 /*
246  * Return true if the machine we're running on is a Positron.
247  * (Positron is an unsupported developers platform.)
248  */
249 int
250 iam_positron(void)
251 {
252 	char model[32];
253 	const char proto_model[] = "SUNW,501-2732";
254 	pnode_t root = prom_rootnode();
255 
256 	if (prom_getproplen(root, "model") != sizeof (proto_model))
257 		return (0);
258 
259 	(void) prom_getprop(root, "model", model);
260 	if (strcmp(model, proto_model) == 0)
261 		return (1);
262 	return (0);
263 }
264 
265 /*
266  * Find a physically contiguous area of twice the largest ecache size
267  * to be used while doing displacement flush of ecaches.
268  */
269 uint64_t
270 ecache_flush_address(void)
271 {
272 	struct memlist *pmem;
273 	uint64_t flush_size;
274 	uint64_t ret_val;
275 
276 	flush_size = ecache_size * 2;
277 	for (pmem = phys_install; pmem; pmem = pmem->next) {
278 		ret_val = P2ROUNDUP(pmem->address, ecache_size);
279 		if (ret_val + flush_size <= pmem->address + pmem->size)
280 			return (ret_val);
281 	}
282 	return ((uint64_t)-1);
283 }
284 
285 /*
286  * Called with the memlist lock held to say that phys_install has
287  * changed.
288  */
289 void
290 phys_install_has_changed(void)
291 {
292 	/*
293 	 * Get the new address into a temporary just in case panicking
294 	 * involves use of ecache_flushaddr.
295 	 */
296 	uint64_t new_addr;
297 
298 	new_addr = ecache_flush_address();
299 	if (new_addr == (uint64_t)-1) {
300 		cmn_err(CE_PANIC,
301 		    "ecache_flush_address(): failed, ecache_size=%x",
302 		    ecache_size);
303 		/*NOTREACHED*/
304 	}
305 	ecache_flushaddr = new_addr;
306 	membar_producer();
307 }
308