xref: /illumos-gate/usr/src/uts/sun4u/schumacher/os/schumacher.c (revision 004388ebfdfe2ed7dfd2d153a876dfcc22d2c006)
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 int (*p2get_mem_unum)(int, uint64_t, char *, int, int *);
41 
42 void
43 startup_platform(void)
44 {
45 }
46 
47 int
48 set_platform_tsb_spares()
49 {
50 	return (0);
51 }
52 
53 void
54 set_platform_defaults(void)
55 {
56 }
57 
58 /*
59  * Definitions for accessing the pci config space of the isa node
60  * of Southbridge.
61  */
62 #define	SCHUMACHER_ISA_PATHNAME	"/pci@1e,600000/isa@7"
63 static ddi_acc_handle_t isa_handle;		/* handle for isa pci space */
64 
65 
66 void
67 load_platform_drivers(void)
68 {
69 	dev_info_t 		*dip;		/* dip of the isa driver */
70 
71 	/*
72 	 * Install 'us' driver.
73 	 */
74 	(void) i_ddi_attach_hw_nodes("us");
75 
76 	/*
77 	 * mc-us3i must stay loaded for plat_get_mem_unum()
78 	 */
79 	if (i_ddi_attach_hw_nodes("mc-us3i") != DDI_SUCCESS)
80 		cmn_err(CE_WARN, "mc-us3i driver failed to install");
81 	(void) ddi_hold_driver(ddi_name_to_major("mc-us3i"));
82 
83 	/*
84 	 * Install Isa driver. This is required for the southbridge IDE
85 	 * workaround - to reset the IDE channel during IDE bus reset.
86 	 * Panic the system in case ISA driver could not be loaded or
87 	 * any problem in accessing its pci config space. Since the register
88 	 * to reset the channel for IDE is in ISA config space!.
89 	 */
90 
91 	dip = e_ddi_hold_devi_by_path(SCHUMACHER_ISA_PATHNAME, 0);
92 	if (dip == NULL) {
93 		cmn_err(CE_PANIC, "Could not install the isa driver\n");
94 		return;
95 	}
96 
97 	if (pci_config_setup(dip, &isa_handle) != DDI_SUCCESS) {
98 		cmn_err(CE_PANIC, "Could not get the config space of isa\n");
99 		return;
100 	}
101 }
102 
103 /*
104  * This routine provides a workaround for a bug in the SB chip which
105  * can cause data corruption. Will be invoked from the IDE HBA driver for
106  * Acer SouthBridge at the time of IDE bus reset.
107  */
108 /*ARGSUSED*/
109 int
110 plat_ide_chipreset(dev_info_t *dip, int chno)
111 {
112 	uint8_t	val;
113 	int	ret = DDI_SUCCESS;
114 
115 	if (isa_handle == NULL) {
116 		return (DDI_FAILURE);
117 	}
118 
119 	val = pci_config_get8(isa_handle, 0x58);
120 	/*
121 	 * The dip passed as the argument is not used here.
122 	 * This will be needed for platforms which have multiple on-board SB,
123 	 * The dip passed will be used to match the corresponding ISA node.
124 	 */
125 	switch (chno) {
126 		case 0:
127 			/*
128 			 * First disable the primary channel then re-enable it.
129 			 * As per ALI no wait should be required in between have
130 			 * given 1ms delay in between to be on safer side.
131 			 * bit 2 of register 0x58 when 0 disable the channel 0.
132 			 * bit 2 of register 0x58 when 1 enables the channel 0.
133 			 */
134 			pci_config_put8(isa_handle, 0x58, val & 0xFB);
135 			drv_usecwait(1000);
136 			pci_config_put8(isa_handle, 0x58, val);
137 			break;
138 		case 1:
139 			/*
140 			 * bit 3 of register 0x58 when 0 disable the channel 1.
141 			 * bit 3 of register 0x58 when 1 enables the channel 1.
142 			 */
143 			pci_config_put8(isa_handle, 0x58, val & 0xF7);
144 			drv_usecwait(1000);
145 			pci_config_put8(isa_handle, 0x58, val);
146 			break;
147 		default:
148 			/*
149 			 * Unknown channel number passed. Return failure.
150 			 */
151 			ret = DDI_FAILURE;
152 	}
153 
154 	return (ret);
155 }
156 
157 
158 /*ARGSUSED*/
159 int
160 plat_cpu_poweron(struct cpu *cp)
161 {
162 	return (ENOTSUP);	/* not supported on this platform */
163 }
164 
165 /*ARGSUSED*/
166 int
167 plat_cpu_poweroff(struct cpu *cp)
168 {
169 	return (ENOTSUP);	/* not supported on this platform */
170 }
171 
172 /*ARGSUSED*/
173 void
174 plat_freelist_process(int mnode)
175 {
176 }
177 
178 char *platform_module_list[] = {
179 	(char *)0
180 };
181 
182 /*ARGSUSED*/
183 void
184 plat_tod_fault(enum tod_fault_type tod_bad)
185 {
186 }
187 
188 /*ARGSUSED*/
189 int
190 plat_get_mem_unum(int synd_code, uint64_t flt_addr, int flt_bus_id,
191     int flt_in_memory, ushort_t flt_status, char *buf, int buflen, int *lenp)
192 {
193 	if (flt_in_memory && (p2get_mem_unum != NULL))
194 		return (p2get_mem_unum(synd_code, P2ALIGN(flt_addr, 8),
195 		    buf, buflen, lenp));
196 	else
197 		return (ENOTSUP);
198 }
199 
200 /*ARGSUSED*/
201 int
202 plat_get_cpu_unum(int cpuid, char *buf, int buflen, int *lenp)
203 {
204 	if (snprintf(buf, buflen, "MB") >= buflen) {
205 		return (ENOSPC);
206 	} else {
207 		*lenp = strlen(buf);
208 		return (0);
209 	}
210 }
211 
212 /*
213  * Fiesta support for lgroups.
214  *
215  * On fiesta platform, an lgroup platform handle == CPU id
216  */
217 
218 /*
219  * Macro for extracting the CPU number from the CPU id
220  */
221 #define	CPUID_TO_LGRP(id)	((id) & 0x7)
222 #define	SCHUMACHER_MC_SHIFT	36
223 
224 /*
225  * Return the platform handle for the lgroup containing the given CPU
226  */
227 lgrp_handle_t
228 plat_lgrp_cpu_to_hand(processorid_t id)
229 {
230 	return (CPUID_TO_LGRP(id));
231 }
232 
233 /*
234  * Platform specific lgroup initialization
235  */
236 void
237 plat_lgrp_init(void)
238 {
239 	pnode_t		curnode;
240 	char		tmp_name[MAXSYSNAME];
241 	int		portid;
242 	int		cpucnt = 0;
243 	int		max_portid = -1;
244 	extern uint32_t lgrp_expand_proc_thresh;
245 	extern uint32_t lgrp_expand_proc_diff;
246 	extern pgcnt_t	lgrp_mem_free_thresh;
247 	extern uint32_t lgrp_loadavg_tolerance;
248 	extern uint32_t lgrp_loadavg_max_effect;
249 	extern uint32_t lgrp_load_thresh;
250 	extern lgrp_mem_policy_t  lgrp_mem_policy_root;
251 
252 	/*
253 	 * Count the number of CPUs installed to determine if
254 	 * NUMA optimization should be enabled or not.
255 	 *
256 	 * All CPU nodes reside in the root node and have a
257 	 * device type "cpu".
258 	 */
259 	curnode = prom_rootnode();
260 	for (curnode = prom_childnode(curnode); curnode;
261 	    curnode = prom_nextnode(curnode)) {
262 		bzero(tmp_name, MAXSYSNAME);
263 		if (prom_getprop(curnode, OBP_NAME, (caddr_t)tmp_name) == -1 ||
264 		    prom_getprop(curnode, OBP_DEVICETYPE, tmp_name) == -1 ||
265 		    strcmp(tmp_name, "cpu") != 0)
266 			continue;
267 
268 		cpucnt++;
269 		if (prom_getprop(curnode, "portid", (caddr_t)&portid) != -1 &&
270 		    portid > max_portid)
271 			max_portid = portid;
272 	}
273 	if (cpucnt <= 1)
274 		max_mem_nodes = 1;
275 	else if (max_portid >= 0 && max_portid < MAX_MEM_NODES)
276 		max_mem_nodes = max_portid + 1;
277 
278 	/*
279 	 * Set tuneables for fiesta architecture
280 	 *
281 	 * lgrp_expand_proc_thresh is the minimum load on the lgroups
282 	 * this process is currently running on before considering
283 	 * expanding threads to another lgroup.
284 	 *
285 	 * lgrp_expand_proc_diff determines how much less the remote lgroup
286 	 * must be loaded before expanding to it.
287 	 *
288 	 * Optimize for memory bandwidth by spreading multi-threaded
289 	 * program to different lgroups.
290 	 */
291 	lgrp_expand_proc_thresh = lgrp_loadavg_max_effect - 1;
292 	lgrp_expand_proc_diff = lgrp_loadavg_max_effect / 2;
293 	lgrp_loadavg_tolerance = lgrp_loadavg_max_effect / 2;
294 	lgrp_mem_free_thresh = 1;	/* home lgrp must have some memory */
295 	lgrp_expand_proc_thresh = lgrp_loadavg_max_effect - 1;
296 	lgrp_mem_policy_root = LGRP_MEM_POLICY_NEXT;
297 	lgrp_load_thresh = 0;
298 
299 	mem_node_pfn_shift = SCHUMACHER_MC_SHIFT - MMU_PAGESHIFT;
300 }
301 
302 /*
303  * Return latency between "from" and "to" lgroups
304  *
305  * This latency number can only be used for relative comparison
306  * between lgroups on the running system, cannot be used across platforms,
307  * and may not reflect the actual latency.  It is platform and implementation
308  * specific, so platform gets to decide its value.  It would be nice if the
309  * number was at least proportional to make comparisons more meaningful though.
310  * NOTE: The numbers below are supposed to be load latencies for uncached
311  * memory divided by 10.
312  */
313 int
314 plat_lgrp_latency(lgrp_handle_t from, lgrp_handle_t to)
315 {
316 	/*
317 	 * Return remote latency when there are more than two lgroups
318 	 * (root and child) and getting latency between two different
319 	 * lgroups or root is involved
320 	 */
321 	if (lgrp_optimizations() && (from != to ||
322 	    from == LGRP_DEFAULT_HANDLE || to == LGRP_DEFAULT_HANDLE))
323 		return (17);
324 	else
325 		return (12);
326 }
327 
328 int
329 plat_pfn_to_mem_node(pfn_t pfn)
330 {
331 	ASSERT(max_mem_nodes > 1);
332 	return (pfn >> mem_node_pfn_shift);
333 }
334 
335 /*
336  * Assign memnode to lgroups
337  */
338 void
339 plat_fill_mc(pnode_t nodeid)
340 {
341 	int		portid;
342 
343 	/*
344 	 * Schumacher memory controller portid == global CPU id
345 	 */
346 	if ((prom_getprop(nodeid, "portid", (caddr_t)&portid) == -1) ||
347 	    (portid < 0))
348 		return;
349 
350 	if (portid < max_mem_nodes)
351 		plat_assign_lgrphand_to_mem_node(portid, portid);
352 }
353 
354 /* ARGSUSED */
355 void
356 plat_build_mem_nodes(u_longlong_t *list, size_t nelems)
357 {
358 	size_t	elem;
359 	pfn_t	basepfn;
360 	pgcnt_t	npgs;
361 
362 	/*
363 	 * Boot install lists are arranged <addr, len>, <addr, len>, ...
364 	 */
365 	for (elem = 0; elem < nelems; elem += 2) {
366 		basepfn = btop(list[elem]);
367 		npgs = btop(list[elem+1]);
368 		mem_node_add_slice(basepfn, basepfn + npgs - 1);
369 	}
370 }
371