xref: /illumos-gate/usr/src/uts/sun4u/chicago/os/chicago.c (revision 30f5cf21f0e4186919b67ac48223d09ca110f8fe)
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 = "todds1337";
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 	 * todds1337 needs early attach
109 	 */
110 	if (i_ddi_attach_hw_nodes("todds1337") != DDI_SUCCESS)
111 		cmn_err(CE_WARN, "todds1337 driver failed to install");
112 }
113 
114 /*ARGSUSED*/
115 int
116 plat_cpu_poweron(struct cpu *cp)
117 {
118 	return (ENOTSUP);	/* not supported on this platform */
119 }
120 
121 /*ARGSUSED*/
122 int
123 plat_cpu_poweroff(struct cpu *cp)
124 {
125 	return (ENOTSUP);	/* not supported on this platform */
126 }
127 
128 /*ARGSUSED*/
129 void
130 plat_freelist_process(int mnode)
131 {
132 }
133 
134 char *platform_module_list[] = {
135 	"mi2cv",
136 	"jbusppm",
137 	"pca9556",
138 	"ppm",
139 	(char *)0
140 };
141 
142 /*ARGSUSED*/
143 void
144 plat_tod_fault(enum tod_fault_type tod_bad)
145 {
146 }
147 
148 /*ARGSUSED*/
149 int
150 plat_get_mem_unum(int synd_code, uint64_t flt_addr, int flt_bus_id,
151     int flt_in_memory, ushort_t flt_status, char *buf, int buflen, int *lenp)
152 {
153 	if (flt_in_memory && (p2get_mem_unum != NULL))
154 		return (p2get_mem_unum(synd_code, P2ALIGN(flt_addr, 8),
155 		    buf, buflen, lenp));
156 	else
157 		return (ENOTSUP);
158 }
159 
160 /*ARGSUSED*/
161 int
162 plat_get_cpu_unum(int cpuid, char *buf, int buflen, int *lenp)
163 {
164 	if (snprintf(buf, buflen, "MB") >= buflen) {
165 		return (ENOSPC);
166 	} else {
167 		*lenp = strlen(buf);
168 		return (0);
169 	}
170 }
171 
172 /*
173  * Fiesta support for lgroups.
174  *
175  * On fiesta platform, an lgroup platform handle == CPU id
176  */
177 
178 /*
179  * Macro for extracting the CPU number from the CPU id
180  */
181 #define	CPUID_TO_LGRP(id)	((id) & 0x7)
182 #define	CHICAGO_MC_SHIFT	36
183 
184 /*
185  * Return the platform handle for the lgroup containing the given CPU
186  */
187 void *
188 plat_lgrp_cpu_to_hand(processorid_t id)
189 {
190 	return ((void *) CPUID_TO_LGRP(id));
191 }
192 
193 /*
194  * Platform specific lgroup initialization
195  */
196 void
197 plat_lgrp_init(void)
198 {
199 	dnode_t		curnode;
200 	char		tmp_name[MAXSYSNAME];
201 	int		portid;
202 	int		cpucnt = 0;
203 	int		max_portid = -1;
204 	extern uint32_t lgrp_expand_proc_thresh;
205 	extern uint32_t lgrp_expand_proc_diff;
206 	extern pgcnt_t	lgrp_mem_free_thresh;
207 	extern uint32_t lgrp_loadavg_tolerance;
208 	extern uint32_t lgrp_loadavg_max_effect;
209 	extern uint32_t lgrp_load_thresh;
210 	extern lgrp_mem_policy_t  lgrp_mem_policy_root;
211 
212 	/*
213 	 * Count the number of CPUs installed to determine if
214 	 * NUMA optimization should be enabled or not.
215 	 *
216 	 * All CPU nodes reside in the root node and have a
217 	 * device type "cpu".
218 	 */
219 	curnode = prom_rootnode();
220 	for (curnode = prom_childnode(curnode); curnode;
221 	    curnode = prom_nextnode(curnode)) {
222 		bzero(tmp_name, MAXSYSNAME);
223 		if (prom_getproplen(curnode, OBP_NAME) < MAXSYSNAME) {
224 			if (prom_getprop(curnode, OBP_NAME,
225 			    (caddr_t)tmp_name) == -1 || prom_getprop(curnode,
226 			    OBP_DEVICETYPE, tmp_name) == -1 || strcmp(tmp_name,
227 			    "cpu") != 0)
228 			continue;
229 
230 			cpucnt++;
231 			if (prom_getprop(curnode, "portid", (caddr_t)&portid) !=
232 			    -1 && portid > max_portid)
233 				max_portid = portid;
234 		}
235 	}
236 	if (cpucnt <= 1)
237 		max_mem_nodes = 1;
238 	else if (max_portid >= 0 && max_portid < MAX_MEM_NODES)
239 		max_mem_nodes = max_portid + 1;
240 
241 	/*
242 	 * Set tuneables for fiesta architecture
243 	 *
244 	 * lgrp_expand_proc_thresh is the minimum load on the lgroups
245 	 * this process is currently running on before considering
246 	 * expanding threads to another lgroup.
247 	 *
248 	 * lgrp_expand_proc_diff determines how much less the remote lgroup
249 	 * must be loaded before expanding to it.
250 	 *
251 	 * Optimize for memory bandwidth by spreading multi-threaded
252 	 * program to different lgroups.
253 	 */
254 	lgrp_expand_proc_thresh = lgrp_loadavg_max_effect - 1;
255 	lgrp_expand_proc_diff = lgrp_loadavg_max_effect / 2;
256 	lgrp_loadavg_tolerance = lgrp_loadavg_max_effect / 2;
257 	lgrp_mem_free_thresh = 1;	/* home lgrp must have some memory */
258 	lgrp_expand_proc_thresh = lgrp_loadavg_max_effect - 1;
259 	lgrp_mem_policy_root = LGRP_MEM_POLICY_NEXT;
260 	lgrp_load_thresh = 0;
261 
262 	mem_node_pfn_shift = CHICAGO_MC_SHIFT - MMU_PAGESHIFT;
263 }
264 
265 /*
266  * Return latency between "from" and "to" lgroups
267  *
268  * This latency number can only be used for relative comparison
269  * between lgroups on the running system, cannot be used across platforms,
270  * and may not reflect the actual latency.  It is platform and implementation
271  * specific, so platform gets to decide its value.  It would be nice if the
272  * number was at least proportional to make comparisons more meaningful though.
273  * NOTE: The numbers below are supposed to be load latencies for uncached
274  * memory divided by 10.
275  */
276 int
277 plat_lgrp_latency(lgrp_handle_t from, lgrp_handle_t to)
278 {
279 	/*
280 	 * Return remote latency when there are more than two lgroups
281 	 * (root and child) and getting latency between two different
282 	 * lgroups or root is involved
283 	 */
284 	if (lgrp_optimizations() && (from != to ||
285 	    from == LGRP_DEFAULT_HANDLE || to == LGRP_DEFAULT_HANDLE))
286 		return (17);
287 	else
288 		return (12);
289 }
290 
291 int
292 plat_pfn_to_mem_node(pfn_t pfn)
293 {
294 	ASSERT(max_mem_nodes > 1);
295 	return (pfn >> mem_node_pfn_shift);
296 }
297 
298 /*
299  * Assign memnode to lgroups
300  */
301 void
302 plat_fill_mc(dnode_t nodeid)
303 {
304 	int		portid;
305 
306 	/*
307 	 * Chicago memory controller portid == global CPU id
308 	 */
309 	if ((prom_getprop(nodeid, "portid", (caddr_t)&portid) == -1) ||
310 	    (portid < 0))
311 		return;
312 
313 	if (portid < max_mem_nodes)
314 		plat_assign_lgrphand_to_mem_node((lgrp_handle_t)portid, portid);
315 }
316 
317 /* ARGSUSED */
318 void
319 plat_build_mem_nodes(u_longlong_t *list, size_t nelems)
320 {
321 	size_t	elem;
322 	pfn_t	basepfn;
323 	pgcnt_t	npgs;
324 
325 	/*
326 	 * Boot install lists are arranged <addr, len>, <addr, len>, ...
327 	 */
328 	for (elem = 0; elem < nelems; elem += 2) {
329 		basepfn = btop(list[elem]);
330 		npgs = btop(list[elem+1]);
331 		mem_node_add_slice(basepfn, basepfn + npgs - 1);
332 	}
333 }
334 
335 /*
336  * Common locking enter code
337  */
338 void
339 plat_setprop_enter(void)
340 {
341 	mutex_enter(&chicago_mi2cv_mutex);
342 }
343 
344 /*
345  * Common locking exit code
346  */
347 void
348 plat_setprop_exit(void)
349 {
350 	mutex_exit(&chicago_mi2cv_mutex);
351 }
352 
353 /*
354  * Called by mi2cv driver
355  */
356 void
357 plat_shared_i2c_enter(dev_info_t *i2cnexus_dip)
358 {
359 	if (i2cnexus_dip == shared_mi2cv_dip) {
360 		plat_setprop_enter();
361 	}
362 }
363 
364 /*
365  * Called by mi2cv driver
366  */
367 void
368 plat_shared_i2c_exit(dev_info_t *i2cnexus_dip)
369 {
370 	if (i2cnexus_dip == shared_mi2cv_dip) {
371 		plat_setprop_exit();
372 	}
373 }
374