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