xref: /illumos-gate/usr/src/uts/sun4u/chicago/os/chicago.c (revision 0dee7919e2f2a6479d16b370af93747b9416b242)
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/param.h>
30 #include <sys/systm.h>
31 #include <sys/sysmacros.h>
32 #include <sys/sunddi.h>
33 #include <sys/esunddi.h>
34 #include <sys/platform_module.h>
35 #include <sys/errno.h>
36 #include <sys/lgrp.h>
37 #include <sys/memnode.h>
38 #include <sys/promif.h>
39 
40 #define	SHARED_MI2CV_PATH "/i2c@1f,520000"
41 static dev_info_t *shared_mi2cv_dip;
42 static kmutex_t chicago_mi2cv_mutex;
43 
44 int (*p2get_mem_unum)(int, uint64_t, char *, int, int *);
45 
46 void
47 startup_platform(void)
48 {
49 	mutex_init(&chicago_mi2cv_mutex, NULL, NULL, NULL);
50 }
51 
52 int
53 set_platform_tsb_spares()
54 {
55 	return (0);
56 }
57 
58 void
59 set_platform_defaults(void)
60 {
61 	extern char *tod_module_name;
62 	/* Set appropriate tod module for Chicago */
63 	if (tod_module_name == NULL)
64 		tod_module_name = "todm5823";
65 }
66 
67 /*
68  * Definitions for accessing the pci config space of the isa node
69  * of Southbridge.
70  */
71 static ddi_acc_handle_t isa_handle = NULL;	/* handle for isa pci space */
72 
73 
74 void
75 load_platform_drivers(void)
76 {
77 	/*
78 	 * Install power driver which handles the power button.
79 	 */
80 	if (i_ddi_attach_hw_nodes("power") != DDI_SUCCESS)
81 		cmn_err(CE_WARN, "Failed to install \"power\" driver.");
82 	(void) ddi_hold_driver(ddi_name_to_major("power"));
83 
84 	/*
85 	 * It is OK to return error because 'us' driver is not available
86 	 * in all clusters (e.g. missing in Core cluster).
87 	 */
88 	(void) i_ddi_attach_hw_nodes("us");
89 
90 	if (i_ddi_attach_hw_nodes("grbeep") != DDI_SUCCESS)
91 		cmn_err(CE_WARN, "Failed to install \"beep\" driver.");
92 
93 
94 	/*
95 	 * mc-us3i must stay loaded for plat_get_mem_unum()
96 	 */
97 	if (i_ddi_attach_hw_nodes("mc-us3i") != DDI_SUCCESS)
98 		cmn_err(CE_WARN, "mc-us3i driver failed to install");
99 	(void) ddi_hold_driver(ddi_name_to_major("mc-us3i"));
100 
101 	/*
102 	 * Figure out which mi2cv dip is shared with OBP for the nvram
103 	 * device, so the lock can be acquired.
104 	 */
105 	shared_mi2cv_dip = e_ddi_hold_devi_by_path(SHARED_MI2CV_PATH, 0);
106 }
107 
108 /*ARGSUSED*/
109 int
110 plat_cpu_poweron(struct cpu *cp)
111 {
112 	return (ENOTSUP);	/* not supported on this platform */
113 }
114 
115 /*ARGSUSED*/
116 int
117 plat_cpu_poweroff(struct cpu *cp)
118 {
119 	return (ENOTSUP);	/* not supported on this platform */
120 }
121 
122 /*ARGSUSED*/
123 void
124 plat_freelist_process(int mnode)
125 {
126 }
127 
128 char *platform_module_list[] = {
129 	"mi2cv",
130 	"jbusppm",
131 	"pca9556",
132 	"ppm",
133 	(char *)0
134 };
135 
136 /*ARGSUSED*/
137 void
138 plat_tod_fault(enum tod_fault_type tod_bad)
139 {
140 }
141 
142 /*ARGSUSED*/
143 int
144 plat_get_mem_unum(int synd_code, uint64_t flt_addr, int flt_bus_id,
145     int flt_in_memory, ushort_t flt_status, char *buf, int buflen, int *lenp)
146 {
147 	if (flt_in_memory && (p2get_mem_unum != NULL))
148 		return (p2get_mem_unum(synd_code, P2ALIGN(flt_addr, 8),
149 		    buf, buflen, lenp));
150 	else
151 		return (ENOTSUP);
152 }
153 
154 /*ARGSUSED*/
155 int
156 plat_get_cpu_unum(int cpuid, char *buf, int buflen, int *lenp)
157 {
158 	if (snprintf(buf, buflen, "MB") >= buflen) {
159 		return (ENOSPC);
160 	} else {
161 		*lenp = strlen(buf);
162 		return (0);
163 	}
164 }
165 
166 /*
167  * Fiesta support for lgroups.
168  *
169  * On fiesta platform, an lgroup platform handle == CPU id
170  */
171 
172 /*
173  * Macro for extracting the CPU number from the CPU id
174  */
175 #define	CPUID_TO_LGRP(id)	((id) & 0x7)
176 #define	CHICAGO_MC_SHIFT	36
177 
178 /*
179  * Return the platform handle for the lgroup containing the given CPU
180  */
181 void *
182 plat_lgrp_cpu_to_hand(processorid_t id)
183 {
184 	return ((void *) CPUID_TO_LGRP(id));
185 }
186 
187 /*
188  * Platform specific lgroup initialization
189  */
190 void
191 plat_lgrp_init(void)
192 {
193 	dnode_t		curnode;
194 	char		tmp_name[MAXSYSNAME];
195 	int		portid;
196 	int		cpucnt = 0;
197 	int		max_portid = -1;
198 	extern uint32_t lgrp_expand_proc_thresh;
199 	extern uint32_t lgrp_expand_proc_diff;
200 	extern pgcnt_t	lgrp_mem_free_thresh;
201 	extern uint32_t lgrp_loadavg_tolerance;
202 	extern uint32_t lgrp_loadavg_max_effect;
203 	extern uint32_t lgrp_load_thresh;
204 	extern lgrp_mem_policy_t  lgrp_mem_policy_root;
205 
206 	/*
207 	 * Count the number of CPUs installed to determine if
208 	 * NUMA optimization should be enabled or not.
209 	 *
210 	 * All CPU nodes reside in the root node and have a
211 	 * device type "cpu".
212 	 */
213 	curnode = prom_rootnode();
214 	for (curnode = prom_childnode(curnode); curnode;
215 	    curnode = prom_nextnode(curnode)) {
216 		bzero(tmp_name, MAXSYSNAME);
217 		if (prom_getproplen(curnode, OBP_NAME) < MAXSYSNAME) {
218 			if (prom_getprop(curnode, OBP_NAME,
219 			    (caddr_t)tmp_name) == -1 || prom_getprop(curnode,
220 			    OBP_DEVICETYPE, tmp_name) == -1 || strcmp(tmp_name,
221 			    "cpu") != 0)
222 			continue;
223 
224 			cpucnt++;
225 			if (prom_getprop(curnode, "portid", (caddr_t)&portid) !=
226 			    -1 && portid > max_portid)
227 				max_portid = portid;
228 		}
229 	}
230 	if (cpucnt <= 1)
231 		max_mem_nodes = 1;
232 	else if (max_portid >= 0 && max_portid < MAX_MEM_NODES)
233 		max_mem_nodes = max_portid + 1;
234 
235 	/*
236 	 * Set tuneables for fiesta architecture
237 	 *
238 	 * lgrp_expand_proc_thresh is the minimum load on the lgroups
239 	 * this process is currently running on before considering
240 	 * expanding threads to another lgroup.
241 	 *
242 	 * lgrp_expand_proc_diff determines how much less the remote lgroup
243 	 * must be loaded before expanding to it.
244 	 *
245 	 * Optimize for memory bandwidth by spreading multi-threaded
246 	 * program to different lgroups.
247 	 */
248 	lgrp_expand_proc_thresh = lgrp_loadavg_max_effect - 1;
249 	lgrp_expand_proc_diff = lgrp_loadavg_max_effect / 2;
250 	lgrp_loadavg_tolerance = lgrp_loadavg_max_effect / 2;
251 	lgrp_mem_free_thresh = 1;	/* home lgrp must have some memory */
252 	lgrp_expand_proc_thresh = lgrp_loadavg_max_effect - 1;
253 	lgrp_mem_policy_root = LGRP_MEM_POLICY_NEXT;
254 	lgrp_load_thresh = 0;
255 
256 	mem_node_pfn_shift = CHICAGO_MC_SHIFT - MMU_PAGESHIFT;
257 }
258 
259 /*
260  * Return latency between "from" and "to" lgroups
261  *
262  * This latency number can only be used for relative comparison
263  * between lgroups on the running system, cannot be used across platforms,
264  * and may not reflect the actual latency.  It is platform and implementation
265  * specific, so platform gets to decide its value.  It would be nice if the
266  * number was at least proportional to make comparisons more meaningful though.
267  * NOTE: The numbers below are supposed to be load latencies for uncached
268  * memory divided by 10.
269  */
270 int
271 plat_lgrp_latency(lgrp_handle_t from, lgrp_handle_t to)
272 {
273 	/*
274 	 * Return remote latency when there are more than two lgroups
275 	 * (root and child) and getting latency between two different
276 	 * lgroups or root is involved
277 	 */
278 	if (lgrp_optimizations() && (from != to ||
279 	    from == LGRP_DEFAULT_HANDLE || to == LGRP_DEFAULT_HANDLE))
280 		return (17);
281 	else
282 		return (12);
283 }
284 
285 int
286 plat_pfn_to_mem_node(pfn_t pfn)
287 {
288 	ASSERT(max_mem_nodes > 1);
289 	return (pfn >> mem_node_pfn_shift);
290 }
291 
292 /*
293  * Assign memnode to lgroups
294  */
295 void
296 plat_fill_mc(dnode_t nodeid)
297 {
298 	int		portid;
299 
300 	/*
301 	 * Chicago memory controller portid == global CPU id
302 	 */
303 	if ((prom_getprop(nodeid, "portid", (caddr_t)&portid) == -1) ||
304 	    (portid < 0))
305 		return;
306 
307 	if (portid < max_mem_nodes)
308 		plat_assign_lgrphand_to_mem_node((lgrp_handle_t)portid, portid);
309 }
310 
311 /* ARGSUSED */
312 void
313 plat_build_mem_nodes(u_longlong_t *list, size_t nelems)
314 {
315 	size_t	elem;
316 	pfn_t	basepfn;
317 	pgcnt_t	npgs;
318 
319 	/*
320 	 * Boot install lists are arranged <addr, len>, <addr, len>, ...
321 	 */
322 	for (elem = 0; elem < nelems; elem += 2) {
323 		basepfn = btop(list[elem]);
324 		npgs = btop(list[elem+1]);
325 		mem_node_add_slice(basepfn, basepfn + npgs - 1);
326 	}
327 }
328 
329 /*
330  * Common locking enter code
331  */
332 void
333 plat_setprop_enter(void)
334 {
335 	mutex_enter(&chicago_mi2cv_mutex);
336 }
337 
338 /*
339  * Common locking exit code
340  */
341 void
342 plat_setprop_exit(void)
343 {
344 	mutex_exit(&chicago_mi2cv_mutex);
345 }
346 
347 /*
348  * Called by mi2cv driver
349  */
350 void
351 plat_shared_i2c_enter(dev_info_t *i2cnexus_dip)
352 {
353 	if (i2cnexus_dip == shared_mi2cv_dip) {
354 		plat_setprop_enter();
355 	}
356 }
357 
358 /*
359  * Called by mi2cv driver
360  */
361 void
362 plat_shared_i2c_exit(dev_info_t *i2cnexus_dip)
363 {
364 	if (i2cnexus_dip == shared_mi2cv_dip) {
365 		plat_setprop_exit();
366 	}
367 }
368