xref: /titanic_51/usr/src/uts/sun4v/os/mach_startup.c (revision 8eea8e29cc4374d1ee24c25a07f45af132db3499)
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/prom_plat.h>
32 #include <sys/promif.h>
33 #include <sys/vm.h>
34 #include <sys/cpu.h>
35 #include <sys/atomic.h>
36 #include <sys/cpupart.h>
37 #include <sys/disp.h>
38 #include <sys/hypervisor_api.h>
39 #ifdef TRAPTRACE
40 #include <sys/traptrace.h>
41 #include <sys/hypervisor_api.h>
42 #endif /* TRAPTRACE */
43 
44 caddr_t	mmu_fault_status_area;
45 
46 extern void sfmmu_set_tsbs(void);
47 /*
48  * CPU IDLE optimization variables/routines
49  */
50 static int enable_halt_idle_cpus = 1;
51 
52 void
53 setup_trap_table(void)
54 {
55 	caddr_t mmfsa_va;
56 	extern	 caddr_t mmu_fault_status_area;
57 	mmfsa_va =
58 	    mmu_fault_status_area + (MMFSA_SIZE * CPU->cpu_id);
59 
60 	intr_init(CPU);			/* init interrupt request free list */
61 	setwstate(WSTATE_KERN);
62 	set_mmfsa_scratchpad(mmfsa_va);
63 	prom_set_mmfsa_traptable(&trap_table, va_to_pa(mmfsa_va));
64 	sfmmu_set_tsbs();
65 }
66 
67 void
68 phys_install_has_changed(void)
69 {
70 
71 }
72 
73 /*
74  * Halt the present CPU until awoken via an interrupt
75  */
76 static void
77 cpu_halt(void)
78 {
79 	cpu_t *cpup = CPU;
80 	processorid_t cpun = cpup->cpu_id;
81 	cpupart_t *cp;
82 	int hset_update = 1;
83 	int s;
84 
85 	/*
86 	 * If this CPU is online, and there's multiple CPUs
87 	 * in the system, then we should notate our halting
88 	 * by adding ourselves to the partition's halted CPU
89 	 * bitmap. This allows other CPUs to find/awaken us when
90 	 * work becomes available.
91 	 */
92 	if (CPU->cpu_flags & CPU_OFFLINE || ncpus == 1)
93 		hset_update = 0;
94 	/*
95 	 * We're on our way to being halted.
96 	 * Raise PIL now, so that we'll awaken immediately
97 	 * after halting if someone tries to poke us between now and
98 	 * the time we actually halt.
99 	 */
100 	s = spl7();
101 
102 	/*
103 	 * Add ourselves to the partition's halted CPUs bitmask
104 	 * if necessary.
105 	 */
106 	if (hset_update) {
107 		cp = cpup->cpu_part;
108 		CPUSET_ATOMIC_ADD(cp->cp_haltset, cpun);
109 	}
110 
111 	/*
112 	 * Check to make sure there's really nothing to do.
113 	 * If work becomes available *after* we do this check
114 	 * and it's determined that the work should be ours,
115 	 * we won't miss it since we'll be notified with a "poke"
116 	 * ...which will pop us right back out of the halted state.
117 	 */
118 	if (disp_anywork()) {
119 		if (hset_update)
120 			CPUSET_ATOMIC_DEL(cp->cp_haltset, cpun);
121 		(void) splx(s);
122 		return;
123 	}
124 
125 	/*
126 	 * Halt the strand
127 	 */
128 	(void) hv_cpu_yield();
129 
130 	/*
131 	 * We're no longer halted
132 	 */
133 	(void) splx(s);
134 	if (hset_update)
135 		CPUSET_ATOMIC_DEL(cp->cp_haltset, cpun);
136 }
137 
138 /*
139  * If "cpu" is halted, then wake it up clearing its halted bit in advance.
140  * Otherwise, see if other CPUs in the cpu partition are halted and need to
141  * be woken up so that they can steal the thread we placed on this CPU.
142  * This function is only used on MP systems.
143  */
144 static void
145 cpu_wakeup(cpu_t *cpu, int bound)
146 {
147 	uint_t		cpu_found;
148 	int		result;
149 	cpupart_t	*cp;
150 
151 	cp = cpu->cpu_part;
152 	if (CPU_IN_SET(cp->cp_haltset, cpu->cpu_id)) {
153 		/*
154 		 * Clear the halted bit for that CPU since it will be
155 		 * poked in a moment.
156 		 */
157 		CPUSET_ATOMIC_DEL(cp->cp_haltset, cpu->cpu_id);
158 		/*
159 		 * We may find the current CPU present in the halted cpuset
160 		 * if we're in the context of an interrupt that occurred
161 		 * before we had a chance to clear our bit in cpu_halt().
162 		 * Poking ourself is obviously unnecessary, since if
163 		 * we're here, we're not halted.
164 		 */
165 		if (cpu != CPU)
166 			poke_cpu(cpu->cpu_id);
167 		return;
168 	} else {
169 		/*
170 		 * This cpu isn't halted, but it's idle or undergoing a
171 		 * context switch. No need to awaken anyone else.
172 		 */
173 		if (cpu->cpu_thread == cpu->cpu_idle_thread ||
174 		    cpu->cpu_disp_flags & CPU_DISP_DONTSTEAL)
175 			return;
176 	}
177 
178 	/*
179 	 * No need to wake up other CPUs if the thread we just enqueued
180 	 * is bound.
181 	 */
182 	if (bound)
183 		return;
184 
185 	/*
186 	 * See if there's any other halted CPUs. If there are, then
187 	 * select one, and awaken it.
188 	 * It's possible that after we find a CPU, somebody else
189 	 * will awaken it before we get the chance.
190 	 * In that case, look again.
191 	 */
192 	do {
193 		CPUSET_FIND(cp->cp_haltset, cpu_found);
194 		if (cpu_found == CPUSET_NOTINSET)
195 			return;
196 
197 		ASSERT(cpu_found >= 0 && cpu_found < NCPU);
198 		CPUSET_ATOMIC_XDEL(cp->cp_haltset, cpu_found, result);
199 	} while (result < 0);
200 
201 	if (cpu_found != CPU->cpu_id)
202 		poke_cpu(cpu_found);
203 }
204 
205 void
206 mach_cpu_halt_idle()
207 {
208 	if (enable_halt_idle_cpus) {
209 		idle_cpu = cpu_halt;
210 		disp_enq_thread = cpu_wakeup;
211 	}
212 }
213 
214 int
215 ndata_alloc_mmfsa(struct memlist *ndata)
216 {
217 	size_t	size;
218 
219 	size = MMFSA_SIZE * max_ncpus;
220 	mmu_fault_status_area = ndata_alloc(ndata, size, ecache_alignsize);
221 	if (mmu_fault_status_area == NULL)
222 		return (-1);
223 	return (0);
224 }
225 
226 void
227 mach_memscrub(void)
228 {
229 	/* no memscrub support for sun4v for now */
230 }
231 
232 void
233 mach_fpras()
234 {
235 	/* no fpras support for sun4v for now */
236 }
237 
238 void
239 mach_hw_copy_limit(void)
240 {
241 	/* HW copy limits set by individual CPU module */
242 }
243 
244 #ifdef TRAPTRACE
245 /*
246  * This function sets up hypervisor traptrace buffer
247  */
248 void
249 htrap_trace_setup(caddr_t buf, int cpuid)
250 {
251 	TRAP_TRACE_CTL	*ctlp;
252 
253 	ctlp = &trap_trace_ctl[cpuid];
254 	ctlp->d.hvaddr_base = buf;
255 	ctlp->d.hlimit = HTRAP_TSIZE;
256 	ctlp->d.hpaddr_base = va_to_pa(buf);
257 }
258 
259 /*
260  * This function configures and enables the hypervisor traptrace buffer
261  */
262 void
263 htrap_trace_register(int cpuid)
264 {
265 	uint64_t ret;
266 	uint64_t prev_buf, prev_bufsize;
267 	uint64_t prev_enable;
268 	uint64_t size;
269 	TRAP_TRACE_CTL	*ctlp;
270 
271 	ret = hv_ttrace_buf_info(&prev_buf, &prev_bufsize);
272 	if ((ret == H_EOK) && (prev_bufsize != 0)) {
273 		cmn_err(CE_CONT,
274 		    "!cpu%d: previous HV traptrace buffer of size 0x%lx "
275 		    "at address 0x%lx", cpuid, prev_bufsize, prev_buf);
276 	}
277 
278 	ctlp = &trap_trace_ctl[cpuid];
279 	ret = hv_ttrace_buf_conf(ctlp->d.hpaddr_base, HTRAP_TSIZE /
280 		(sizeof (struct htrap_trace_record)), &size);
281 	if (ret == H_EOK) {
282 		ret = hv_ttrace_enable((uint64_t)TRAP_TENABLE_ALL,
283 			&prev_enable);
284 		if (ret != H_EOK) {
285 			cmn_err(CE_WARN,
286 			    "!cpu%d: HV traptracing not enabled, "
287 			    "ta: 0x%x returned error: %d",
288 			    cpuid, TTRACE_ENABLE, ret);
289 		}
290 	} else {
291 		cmn_err(CE_WARN,
292 		    "!cpu%d: HV traptrace buffer not configured, "
293 		    "ta: 0x%x returned error: %d",
294 		    cpuid, TTRACE_BUF_CONF, ret);
295 	}
296 	/* set hvaddr_base to NULL when traptrace buffer registration fails */
297 	if (ret != H_EOK) {
298 		ctlp->d.hvaddr_base = NULL;
299 		ctlp->d.hlimit = 0;
300 		ctlp->d.hpaddr_base = NULL;
301 	}
302 }
303 #endif /* TRAPTRACE */
304