xref: /onnv-gate/usr/src/uts/sun4u/boston/os/boston.c (revision 11311:639e7bc0b42f)
11121Sjroberts /*
21121Sjroberts  * CDDL HEADER START
31121Sjroberts  *
41121Sjroberts  * The contents of this file are subject to the terms of the
51121Sjroberts  * Common Development and Distribution License (the "License").
61121Sjroberts  * You may not use this file except in compliance with the License.
71121Sjroberts  *
81121Sjroberts  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91121Sjroberts  * or http://www.opensolaris.org/os/licensing.
101121Sjroberts  * See the License for the specific language governing permissions
111121Sjroberts  * and limitations under the License.
121121Sjroberts  *
131121Sjroberts  * When distributing Covered Code, include this CDDL HEADER in each
141121Sjroberts  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151121Sjroberts  * If applicable, add the following below this CDDL HEADER, with the
161121Sjroberts  * fields enclosed by brackets "[]" replaced with your own identifying
171121Sjroberts  * information: Portions Copyright [yyyy] [name of copyright owner]
181121Sjroberts  *
191121Sjroberts  * CDDL HEADER END
201121Sjroberts  */
211121Sjroberts 
22920Sjbeloro /*
23*11311SSurya.Prakki@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24920Sjbeloro  * Use is subject to license terms.
25920Sjbeloro  */
26920Sjbeloro 
27920Sjbeloro #include <sys/param.h>
28920Sjbeloro #include <sys/systm.h>
29920Sjbeloro #include <sys/sysmacros.h>
30920Sjbeloro #include <sys/sunddi.h>
31920Sjbeloro #include <sys/esunddi.h>
32920Sjbeloro 
33920Sjbeloro #include <sys/platform_module.h>
34920Sjbeloro #include <sys/errno.h>
35920Sjbeloro #include <sys/cpu_sgnblk_defs.h>
36920Sjbeloro #include <sys/rmc_comm_dp.h>
37920Sjbeloro #include <sys/rmc_comm_drvintf.h>
38920Sjbeloro #include <sys/modctl.h>
39920Sjbeloro #include <sys/lgrp.h>
40920Sjbeloro #include <sys/memnode.h>
41920Sjbeloro #include <sys/promif.h>
42920Sjbeloro 
43920Sjbeloro #define	SHARED_MI2CV_PATH "/i2c@1f,520000"
44920Sjbeloro static dev_info_t *shared_mi2cv_dip;
45920Sjbeloro static kmutex_t mi2cv_mutex;
46920Sjbeloro 
47920Sjbeloro int (*p2get_mem_unum)(int, uint64_t, char *, int, int *);
48920Sjbeloro static void cpu_sgn_update(ushort_t, uchar_t, uchar_t, int);
49920Sjbeloro int (*rmc_req_now)(rmc_comm_msg_t *, uint8_t) = NULL;
50920Sjbeloro 
51920Sjbeloro void
startup_platform(void)52920Sjbeloro startup_platform(void)
53920Sjbeloro {
54920Sjbeloro 	mutex_init(&mi2cv_mutex, NULL, NULL, NULL);
55920Sjbeloro }
56920Sjbeloro 
57920Sjbeloro int
set_platform_tsb_spares()58920Sjbeloro set_platform_tsb_spares()
59920Sjbeloro {
60920Sjbeloro 	return (0);
61920Sjbeloro }
62920Sjbeloro 
63920Sjbeloro void
set_platform_defaults(void)64920Sjbeloro set_platform_defaults(void)
65920Sjbeloro {
66920Sjbeloro 	extern char *tod_module_name;
67920Sjbeloro 	/* Set appropriate tod module */
68920Sjbeloro 	if (tod_module_name == NULL)
69920Sjbeloro 		tod_module_name = "todm5823";
70920Sjbeloro 
71920Sjbeloro 	cpu_sgn_func = cpu_sgn_update;
72920Sjbeloro }
73920Sjbeloro 
74920Sjbeloro /*
752558Szx151605  * these two dummy functions are loaded over the original
762558Szx151605  * todm5823 set and clear_power_alarm functions. On Boston
772558Szx151605  * these functions are not supported, and thus we need to provide
782558Szx151605  * dummy functions that just returns.
792558Szx151605  * On Boston, clock chip is not persistant across reboots,
802558Szx151605  * and moreover it has a bug sending memory access.
812558Szx151605  * This fix is done by writing over the original
822558Szx151605  * tod_ops function pointer with our dummy replacement functions.
832558Szx151605  */
842558Szx151605 /*ARGSUSED*/
852558Szx151605 static void
dummy_todm5823_set_power_alarm(timestruc_t ts)862558Szx151605 dummy_todm5823_set_power_alarm(timestruc_t ts)
872558Szx151605 {
882558Szx151605 }
892558Szx151605 
902558Szx151605 static void
dummy_todm5823_clear_power_alarm(void)912558Szx151605 dummy_todm5823_clear_power_alarm(void)
922558Szx151605 {
932558Szx151605 }
942558Szx151605 
952558Szx151605 /*
96920Sjbeloro  * Definitions for accessing the pci config space of the isa node
97920Sjbeloro  * of Southbridge.
98920Sjbeloro  */
99920Sjbeloro static ddi_acc_handle_t isa_handle = NULL;	/* handle for isa pci space */
100920Sjbeloro 
101920Sjbeloro /*
102920Sjbeloro  * Definition for accessing rmclomv
103920Sjbeloro  */
104920Sjbeloro #define	RMCLOMV_PATHNAME	"/pseudo/rmclomv@0"
105920Sjbeloro 
106920Sjbeloro void
load_platform_drivers(void)107920Sjbeloro load_platform_drivers(void)
108920Sjbeloro {
109920Sjbeloro 	/*
110920Sjbeloro 	 * It is OK to return error because 'us' driver is not available
111920Sjbeloro 	 * in all clusters (e.g. missing in Core cluster).
112920Sjbeloro 	 */
113920Sjbeloro 	(void) i_ddi_attach_hw_nodes("us");
114920Sjbeloro 
115920Sjbeloro 
116920Sjbeloro 	/*
117920Sjbeloro 	 * mc-us3i must stay loaded for plat_get_mem_unum()
118920Sjbeloro 	 */
119920Sjbeloro 	if (i_ddi_attach_hw_nodes("mc-us3i") != DDI_SUCCESS)
120920Sjbeloro 		cmn_err(CE_WARN, "mc-us3i driver failed to install");
121920Sjbeloro 	(void) ddi_hold_driver(ddi_name_to_major("mc-us3i"));
122920Sjbeloro 
123920Sjbeloro 	/*
124920Sjbeloro 	 * load the power button driver
125920Sjbeloro 	 */
126920Sjbeloro 	if (i_ddi_attach_hw_nodes("power") != DDI_SUCCESS)
127920Sjbeloro 		cmn_err(CE_WARN, "power button driver failed to install");
128920Sjbeloro 	(void) ddi_hold_driver(ddi_name_to_major("power"));
129920Sjbeloro 
130920Sjbeloro 	/*
131920Sjbeloro 	 * load the GPIO driver for the ALOM reset and watchdog lines
132920Sjbeloro 	 */
133920Sjbeloro 	if (i_ddi_attach_hw_nodes("pmugpio") != DDI_SUCCESS)
134920Sjbeloro 		cmn_err(CE_WARN, "pmugpio failed to install");
135920Sjbeloro 	else {
136920Sjbeloro 		extern int watchdog_enable, watchdog_available;
137920Sjbeloro 		extern int disable_watchdog_on_exit;
138920Sjbeloro 
139920Sjbeloro 		/*
140920Sjbeloro 		 * Disable an active h/w watchdog timer upon exit to OBP.
141920Sjbeloro 		 */
142920Sjbeloro 		disable_watchdog_on_exit = 1;
143920Sjbeloro 
144920Sjbeloro 		watchdog_enable = 1;
145920Sjbeloro 		watchdog_available = 1;
146920Sjbeloro 	}
147920Sjbeloro 	(void) ddi_hold_driver(ddi_name_to_major("pmugpio"));
148920Sjbeloro 
149920Sjbeloro 	/*
150920Sjbeloro 	 * Figure out which mi2cv dip is shared with OBP for the nvram
151920Sjbeloro 	 * device, so the lock can be acquired.
152920Sjbeloro 	 */
153920Sjbeloro 	shared_mi2cv_dip = e_ddi_hold_devi_by_path(SHARED_MI2CV_PATH, 0);
154920Sjbeloro 
155920Sjbeloro 	/*
156920Sjbeloro 	 * Load the environmentals driver (rmclomv)
157920Sjbeloro 	 *
158920Sjbeloro 	 * We need this driver to handle events from the RMC when state
159920Sjbeloro 	 * changes occur in the environmental data.
160920Sjbeloro 	 */
161920Sjbeloro 	if (i_ddi_attach_hw_nodes("rmc_comm") != DDI_SUCCESS) {
162920Sjbeloro 		cmn_err(CE_WARN, "rmc_comm failed to install");
163920Sjbeloro 	} else {
164920Sjbeloro 		(void) ddi_hold_driver(ddi_name_to_major("rmc_comm"));
165920Sjbeloro 
166920Sjbeloro 		if (e_ddi_hold_devi_by_path(RMCLOMV_PATHNAME, 0) == NULL) {
167920Sjbeloro 			cmn_err(CE_WARN, "Could not install rmclomv driver\n");
168920Sjbeloro 		}
169920Sjbeloro 	}
1702558Szx151605 
1712558Szx151605 	/*
1722558Szx151605 	 * These two dummy functions are loaded over the original
1732558Szx151605 	 * todm5823 set and clear_power_alarm functions. On Boston,
1742558Szx151605 	 * these functionalities are not supported.
1752558Szx151605 	 * The load_platform_drivers(void) is called from post_startup()
1762558Szx151605 	 * which is after all the initialization of the tod module is
1772558Szx151605 	 * finished, then we replace 2 of the tod_ops function pointers
1782558Szx151605 	 * with our dummy version.
1792558Szx151605 	 */
1802558Szx151605 	tod_ops.tod_set_power_alarm = dummy_todm5823_set_power_alarm;
1812558Szx151605 	tod_ops.tod_clear_power_alarm = dummy_todm5823_clear_power_alarm;
1822558Szx151605 
183920Sjbeloro 	/*
184920Sjbeloro 	 * create a handle to the rmc_comm_request_nowait() function
185920Sjbeloro 	 * inside the rmc_comm module.
186920Sjbeloro 	 *
187920Sjbeloro 	 * The Seattle/Boston todm5823 driver will use this handle to
188920Sjbeloro 	 * use the rmc_comm_request_nowait() function to send time/date
189920Sjbeloro 	 * updates to ALOM.
190920Sjbeloro 	 */
191920Sjbeloro 	rmc_req_now = (int (*)(rmc_comm_msg_t *, uint8_t))
1925648Ssetje 	    modgetsymvalue("rmc_comm_request_nowait", 0);
193920Sjbeloro }
194920Sjbeloro 
195920Sjbeloro /*
196920Sjbeloro  * This routine is needed if a device error or timeout occurs before the
197920Sjbeloro  * driver is loaded.
198920Sjbeloro  */
199920Sjbeloro /*ARGSUSED*/
200920Sjbeloro int
plat_ide_chipreset(dev_info_t * dip,int chno)201920Sjbeloro plat_ide_chipreset(dev_info_t *dip, int chno)
202920Sjbeloro {
203920Sjbeloro 	int	ret = DDI_SUCCESS;
204920Sjbeloro 
205920Sjbeloro 	if (isa_handle == NULL) {
206920Sjbeloro 		return (DDI_FAILURE);
207920Sjbeloro 	}
208920Sjbeloro 
209920Sjbeloro 	/*
210920Sjbeloro 	 * This will be filled in with the reset logic
211920Sjbeloro 	 * for the ULI1573 when that becomes available.
212920Sjbeloro 	 * currently this is just a stub.
213920Sjbeloro 	 */
214920Sjbeloro 	return (ret);
215920Sjbeloro }
216920Sjbeloro 
217920Sjbeloro 
218920Sjbeloro /*ARGSUSED*/
219920Sjbeloro int
plat_cpu_poweron(struct cpu * cp)220920Sjbeloro plat_cpu_poweron(struct cpu *cp)
221920Sjbeloro {
222920Sjbeloro 	return (ENOTSUP);	/* not supported on this platform */
223920Sjbeloro }
224920Sjbeloro 
225920Sjbeloro /*ARGSUSED*/
226920Sjbeloro int
plat_cpu_poweroff(struct cpu * cp)227920Sjbeloro plat_cpu_poweroff(struct cpu *cp)
228920Sjbeloro {
229920Sjbeloro 	return (ENOTSUP);	/* not supported on this platform */
230920Sjbeloro }
231920Sjbeloro 
232920Sjbeloro /*ARGSUSED*/
233920Sjbeloro void
plat_freelist_process(int mnode)234920Sjbeloro plat_freelist_process(int mnode)
235920Sjbeloro {
236920Sjbeloro }
237920Sjbeloro 
238920Sjbeloro char *platform_module_list[] = {
239920Sjbeloro 	"mi2cv",
240920Sjbeloro 	"pca9556",
241920Sjbeloro 	(char *)0
242920Sjbeloro };
243920Sjbeloro 
244920Sjbeloro /*ARGSUSED*/
245920Sjbeloro void
plat_tod_fault(enum tod_fault_type tod_bad)246920Sjbeloro plat_tod_fault(enum tod_fault_type tod_bad)
247920Sjbeloro {
248920Sjbeloro }
249920Sjbeloro 
250920Sjbeloro /*ARGSUSED*/
251920Sjbeloro int
plat_get_mem_unum(int synd_code,uint64_t flt_addr,int flt_bus_id,int flt_in_memory,ushort_t flt_status,char * buf,int buflen,int * lenp)252920Sjbeloro plat_get_mem_unum(int synd_code, uint64_t flt_addr, int flt_bus_id,
253920Sjbeloro     int flt_in_memory, ushort_t flt_status, char *buf, int buflen, int *lenp)
254920Sjbeloro {
255920Sjbeloro 	if (flt_in_memory && (p2get_mem_unum != NULL))
256920Sjbeloro 		return (p2get_mem_unum(synd_code, P2ALIGN(flt_addr, 8),
257920Sjbeloro 		    buf, buflen, lenp));
258920Sjbeloro 	else
259920Sjbeloro 		return (ENOTSUP);
260920Sjbeloro }
261920Sjbeloro 
262920Sjbeloro /*
263920Sjbeloro  * This platform hook gets called from mc_add_mem_unum_label() in the mc-us3i
264920Sjbeloro  * driver giving each platform the opportunity to add platform
265920Sjbeloro  * specific label information to the unum for ECC error logging purposes.
266920Sjbeloro  */
267920Sjbeloro /*ARGSUSED*/
268920Sjbeloro void
plat_add_mem_unum_label(char * unum,int mcid,int bank,int dimm)269920Sjbeloro plat_add_mem_unum_label(char *unum, int mcid, int bank, int dimm)
270920Sjbeloro {
271920Sjbeloro 	char old_unum[UNUM_NAMLEN];
272920Sjbeloro 	int printed;
273920Sjbeloro 	int buflen = UNUM_NAMLEN;
274920Sjbeloro 
275*11311SSurya.Prakki@Sun.COM 	(void) strcpy(old_unum, unum);
2761185Sjroberts 	printed = snprintf(unum, buflen, "MB/C%d/P0/B%d", mcid, bank);
277920Sjbeloro 	buflen -= printed;
278920Sjbeloro 	unum += printed;
279920Sjbeloro 
280920Sjbeloro 	if (dimm != -1) {
281920Sjbeloro 		printed = snprintf(unum, buflen, "/D%d", dimm);
282920Sjbeloro 		buflen -= printed;
283920Sjbeloro 		unum += printed;
284920Sjbeloro 	}
285920Sjbeloro 
286*11311SSurya.Prakki@Sun.COM 	(void) snprintf(unum, buflen, ": %s", old_unum);
287920Sjbeloro }
288920Sjbeloro 
289920Sjbeloro /*ARGSUSED*/
290920Sjbeloro int
plat_get_cpu_unum(int cpuid,char * buf,int buflen,int * lenp)291920Sjbeloro plat_get_cpu_unum(int cpuid, char *buf, int buflen, int *lenp)
292920Sjbeloro {
2931302Sjroberts 	if (snprintf(buf, buflen, "MB/C%d", cpuid) >= buflen) {
294920Sjbeloro 		return (ENOSPC);
295920Sjbeloro 	} else {
296920Sjbeloro 		*lenp = strlen(buf);
297920Sjbeloro 		return (0);
298920Sjbeloro 	}
299920Sjbeloro }
300920Sjbeloro 
301920Sjbeloro /*
302920Sjbeloro  * Our nodename has been set, pass it along to the RMC.
303920Sjbeloro  */
304920Sjbeloro void
plat_nodename_set(void)305920Sjbeloro plat_nodename_set(void)
306920Sjbeloro {
307920Sjbeloro 	rmc_comm_msg_t	req;	/* request */
308920Sjbeloro 	int (*rmc_req_res)(rmc_comm_msg_t *, rmc_comm_msg_t *, time_t) = NULL;
309920Sjbeloro 
310920Sjbeloro 	/*
311920Sjbeloro 	 * find the symbol for the mailbox routine
312920Sjbeloro 	 */
313920Sjbeloro 	rmc_req_res = (int (*)(rmc_comm_msg_t *, rmc_comm_msg_t *, time_t))
3145648Ssetje 	    modgetsymvalue("rmc_comm_request_response", 0);
315920Sjbeloro 
316920Sjbeloro 	if (rmc_req_res == NULL) {
317920Sjbeloro 		return;
318920Sjbeloro 	}
319920Sjbeloro 
320920Sjbeloro 	/*
321920Sjbeloro 	 * construct the message telling the RMC our nodename
322920Sjbeloro 	 */
323920Sjbeloro 	req.msg_type = DP_SET_CPU_NODENAME;
324920Sjbeloro 	req.msg_len = strlen(utsname.nodename) + 1;
325920Sjbeloro 	req.msg_bytes = 0;
326920Sjbeloro 	req.msg_buf = (caddr_t)utsname.nodename;
327920Sjbeloro 
328920Sjbeloro 	/*
329920Sjbeloro 	 * ship it
330920Sjbeloro 	 */
331920Sjbeloro 	(void) (rmc_req_res)(&req, NULL, 2000);
332920Sjbeloro }
333920Sjbeloro 
334920Sjbeloro sig_state_t current_sgn;
335920Sjbeloro 
336920Sjbeloro /*
337920Sjbeloro  * cpu signatures - we're only interested in the overall system
338920Sjbeloro  * "signature" on this platform - not individual cpu signatures
339920Sjbeloro  */
340920Sjbeloro /*ARGSUSED*/
341920Sjbeloro static void
cpu_sgn_update(ushort_t sig,uchar_t state,uchar_t sub_state,int cpuid)342920Sjbeloro cpu_sgn_update(ushort_t sig, uchar_t state, uchar_t sub_state, int cpuid)
343920Sjbeloro {
344920Sjbeloro 	dp_cpu_signature_t signature;
345920Sjbeloro 	rmc_comm_msg_t	req;	/* request */
346920Sjbeloro 	int (*rmc_req_now)(rmc_comm_msg_t *, uint8_t) = NULL;
347920Sjbeloro 
348920Sjbeloro 
349920Sjbeloro 	/*
350920Sjbeloro 	 * Differentiate a panic reboot from a non-panic reboot in the
351920Sjbeloro 	 * setting of the substate of the signature.
352920Sjbeloro 	 *
353920Sjbeloro 	 * If the new substate is REBOOT and we're rebooting due to a panic,
354920Sjbeloro 	 * then set the new substate to a special value indicating a panic
355920Sjbeloro 	 * reboot, SIGSUBST_PANIC_REBOOT.
356920Sjbeloro 	 *
357920Sjbeloro 	 * A panic reboot is detected by a current (previous) signature
358920Sjbeloro 	 * state of SIGST_EXIT, and a new signature substate of SIGSUBST_REBOOT.
359920Sjbeloro 	 * The domain signature state SIGST_EXIT is used as the panic flow
360920Sjbeloro 	 * progresses.
361920Sjbeloro 	 *
362920Sjbeloro 	 * At the end of the panic flow, the reboot occurs but we should know
363920Sjbeloro 	 * one that was involuntary, something that may be quite useful to know
364920Sjbeloro 	 * at OBP level.
365920Sjbeloro 	 */
366920Sjbeloro 	if (state == SIGST_EXIT && sub_state == SIGSUBST_REBOOT) {
367920Sjbeloro 		if (current_sgn.state_t.state == SIGST_EXIT &&
368920Sjbeloro 		    current_sgn.state_t.sub_state != SIGSUBST_REBOOT)
369920Sjbeloro 			sub_state = SIGSUBST_PANIC_REBOOT;
370920Sjbeloro 	}
371920Sjbeloro 
372920Sjbeloro 	/*
373920Sjbeloro 	 * offline and detached states only apply to a specific cpu
374920Sjbeloro 	 * so ignore them.
375920Sjbeloro 	 */
376920Sjbeloro 	if (state == SIGST_OFFLINE || state == SIGST_DETACHED) {
377920Sjbeloro 		return;
378920Sjbeloro 	}
379920Sjbeloro 
380920Sjbeloro 	current_sgn.signature = CPU_SIG_BLD(sig, state, sub_state);
381920Sjbeloro 
382920Sjbeloro 	/*
383920Sjbeloro 	 * find the symbol for the mailbox routine
384920Sjbeloro 	 */
385920Sjbeloro 	rmc_req_now = (int (*)(rmc_comm_msg_t *, uint8_t))
3865648Ssetje 	    modgetsymvalue("rmc_comm_request_nowait", 0);
387920Sjbeloro 	if (rmc_req_now == NULL) {
388920Sjbeloro 		return;
389920Sjbeloro 	}
390920Sjbeloro 
391920Sjbeloro 	signature.cpu_id = -1;
392920Sjbeloro 	signature.sig = sig;
393920Sjbeloro 	signature.states = state;
394920Sjbeloro 	signature.sub_state = sub_state;
395920Sjbeloro 	req.msg_type = DP_SET_CPU_SIGNATURE;
396920Sjbeloro 	req.msg_len = (int)(sizeof (signature));
397920Sjbeloro 	req.msg_bytes = 0;
398920Sjbeloro 	req.msg_buf = (caddr_t)&signature;
399920Sjbeloro 
400920Sjbeloro 	/*
4014052Sphilippm 	 * We need to tell the SP that the host is about to stop running.  The
4024052Sphilippm 	 * SP will then allow the date to be set at its console, it will change
4034052Sphilippm 	 * state of the activity indicator, it will display the correct host
4044052Sphilippm 	 * status, and it will stop sending console messages and alerts to the
4054052Sphilippm 	 * host communication channel.
4064052Sphilippm 	 *
4074052Sphilippm 	 * This requires the RMC_COMM_DREQ_URGENT as we want to
4084052Sphilippm 	 * be sure activity indicators will reflect the correct status.
4094052Sphilippm 	 *
4104052Sphilippm 	 * When sub_state SIGSUBST_DUMP is sent, the urgent flag
4114052Sphilippm 	 * (RMC_COMM_DREQ_URGENT) is not required as SIGSUBST_PANIC_REBOOT
4124052Sphilippm 	 * has already been sent and changed activity indicators.
413920Sjbeloro 	 */
414920Sjbeloro 	if (state == SIGST_EXIT && (sub_state == SIGSUBST_HALT ||
415920Sjbeloro 	    sub_state == SIGSUBST_REBOOT || sub_state == SIGSUBST_ENVIRON ||
416920Sjbeloro 	    sub_state == SIGSUBST_PANIC_REBOOT))
417920Sjbeloro 		(void) (rmc_req_now)(&req, RMC_COMM_DREQ_URGENT);
418920Sjbeloro 	else
4191779Sfw157321 		(void) (rmc_req_now)(&req, 0);
420920Sjbeloro }
421920Sjbeloro 
422920Sjbeloro /*
423920Sjbeloro  * Fiesta support for lgroups.
424920Sjbeloro  *
425920Sjbeloro  * On fiesta platform, an lgroup platform handle == CPU id
426920Sjbeloro  */
427920Sjbeloro 
428920Sjbeloro /*
429920Sjbeloro  * Macro for extracting the CPU number from the CPU id
430920Sjbeloro  */
431920Sjbeloro #define	CPUID_TO_LGRP(id)	((id) & 0x7)
432920Sjbeloro #define	PLATFORM_MC_SHIFT	36
433920Sjbeloro 
434920Sjbeloro /*
435920Sjbeloro  * Return the platform handle for the lgroup containing the given CPU
436920Sjbeloro  */
437920Sjbeloro void *
plat_lgrp_cpu_to_hand(processorid_t id)438920Sjbeloro plat_lgrp_cpu_to_hand(processorid_t id)
439920Sjbeloro {
440969Sanovick 	return ((void *)(uintptr_t)CPUID_TO_LGRP(id));
441920Sjbeloro }
442920Sjbeloro 
443920Sjbeloro /*
444920Sjbeloro  * Platform specific lgroup initialization
445920Sjbeloro  */
446920Sjbeloro void
plat_lgrp_init(void)447920Sjbeloro plat_lgrp_init(void)
448920Sjbeloro {
449920Sjbeloro 	pnode_t		curnode;
4501297Sanovick 	char		tmp_name[sizeof (OBP_CPU) + 1];  /* extra padding */
451920Sjbeloro 	int		portid;
452920Sjbeloro 	int		cpucnt = 0;
453920Sjbeloro 	int		max_portid = -1;
454920Sjbeloro 	extern uint32_t lgrp_expand_proc_thresh;
455920Sjbeloro 	extern uint32_t lgrp_expand_proc_diff;
456920Sjbeloro 	extern pgcnt_t	lgrp_mem_free_thresh;
457920Sjbeloro 	extern uint32_t lgrp_loadavg_tolerance;
458920Sjbeloro 	extern uint32_t lgrp_loadavg_max_effect;
459920Sjbeloro 	extern uint32_t lgrp_load_thresh;
460920Sjbeloro 	extern lgrp_mem_policy_t  lgrp_mem_policy_root;
461920Sjbeloro 
462920Sjbeloro 	/*
463920Sjbeloro 	 * Count the number of CPUs installed to determine if
464920Sjbeloro 	 * NUMA optimization should be enabled or not.
465920Sjbeloro 	 *
466920Sjbeloro 	 * All CPU nodes reside in the root node and have a
467920Sjbeloro 	 * device type "cpu".
468920Sjbeloro 	 */
469920Sjbeloro 	curnode = prom_rootnode();
470920Sjbeloro 	for (curnode = prom_childnode(curnode); curnode;
471920Sjbeloro 	    curnode = prom_nextnode(curnode)) {
4721297Sanovick 		bzero(tmp_name,  sizeof (tmp_name));
4731297Sanovick 		if (prom_bounded_getprop(curnode, OBP_DEVICETYPE, tmp_name,
4741297Sanovick 		    sizeof (OBP_CPU)) == -1 || strcmp(tmp_name, OBP_CPU) != 0)
475920Sjbeloro 			continue;
476920Sjbeloro 
4771297Sanovick 		cpucnt++;
4781297Sanovick 
4791297Sanovick 		if (prom_getprop(curnode, "portid", (caddr_t)&portid) !=
4801297Sanovick 		    -1 && portid > max_portid)
4811297Sanovick 			max_portid = portid;
482920Sjbeloro 	}
483920Sjbeloro 	if (cpucnt <= 1)
484920Sjbeloro 		max_mem_nodes = 1;
485920Sjbeloro 	else if (max_portid >= 0 && max_portid < MAX_MEM_NODES)
486920Sjbeloro 		max_mem_nodes = max_portid + 1;
487920Sjbeloro 
488920Sjbeloro 	/*
489920Sjbeloro 	 * Set tuneables for fiesta architecture
490920Sjbeloro 	 *
491920Sjbeloro 	 * lgrp_expand_proc_thresh is the minimum load on the lgroups
492920Sjbeloro 	 * this process is currently running on before considering
493920Sjbeloro 	 * expanding threads to another lgroup.
494920Sjbeloro 	 *
495920Sjbeloro 	 * lgrp_expand_proc_diff determines how much less the remote lgroup
496920Sjbeloro 	 * must be loaded before expanding to it.
497920Sjbeloro 	 *
498920Sjbeloro 	 * Optimize for memory bandwidth by spreading multi-threaded
499920Sjbeloro 	 * program to different lgroups.
500920Sjbeloro 	 */
501920Sjbeloro 	lgrp_expand_proc_thresh = lgrp_loadavg_max_effect - 1;
502920Sjbeloro 	lgrp_expand_proc_diff = lgrp_loadavg_max_effect / 2;
503920Sjbeloro 	lgrp_loadavg_tolerance = lgrp_loadavg_max_effect / 2;
504920Sjbeloro 	lgrp_mem_free_thresh = 1;	/* home lgrp must have some memory */
505920Sjbeloro 	lgrp_expand_proc_thresh = lgrp_loadavg_max_effect - 1;
506920Sjbeloro 	lgrp_mem_policy_root = LGRP_MEM_POLICY_NEXT;
507920Sjbeloro 	lgrp_load_thresh = 0;
508920Sjbeloro 
509920Sjbeloro 	mem_node_pfn_shift = PLATFORM_MC_SHIFT - MMU_PAGESHIFT;
510920Sjbeloro }
511920Sjbeloro 
512920Sjbeloro /*
513920Sjbeloro  * Return latency between "from" and "to" lgroups
514920Sjbeloro  *
515920Sjbeloro  * This latency number can only be used for relative comparison
516920Sjbeloro  * between lgroups on the running system, cannot be used across platforms,
517920Sjbeloro  * and may not reflect the actual latency.  It is platform and implementation
518920Sjbeloro  * specific, so platform gets to decide its value.  It would be nice if the
519920Sjbeloro  * number was at least proportional to make comparisons more meaningful though.
520920Sjbeloro  * NOTE: The numbers below are supposed to be load latencies for uncached
521920Sjbeloro  * memory divided by 10.
522920Sjbeloro  */
523920Sjbeloro int
plat_lgrp_latency(void * from,void * to)524920Sjbeloro plat_lgrp_latency(void *from, void *to)
525920Sjbeloro {
526920Sjbeloro 	/*
527920Sjbeloro 	 * Return remote latency when there are more than two lgroups
528920Sjbeloro 	 * (root and child) and getting latency between two different
529920Sjbeloro 	 * lgroups or root is involved
530920Sjbeloro 	 */
531920Sjbeloro 	if (lgrp_optimizations() && (from != to || from ==
532920Sjbeloro 	    (void *) LGRP_DEFAULT_HANDLE || to == (void *) LGRP_DEFAULT_HANDLE))
533920Sjbeloro 		return (17);
534920Sjbeloro 	else
535920Sjbeloro 		return (12);
536920Sjbeloro }
537920Sjbeloro 
538920Sjbeloro int
plat_pfn_to_mem_node(pfn_t pfn)539920Sjbeloro plat_pfn_to_mem_node(pfn_t pfn)
540920Sjbeloro {
541920Sjbeloro 	ASSERT(max_mem_nodes > 1);
542920Sjbeloro 	return (pfn >> mem_node_pfn_shift);
543920Sjbeloro }
544920Sjbeloro 
545920Sjbeloro /*
546920Sjbeloro  * Assign memnode to lgroups
547920Sjbeloro  */
548920Sjbeloro void
plat_fill_mc(pnode_t nodeid)549920Sjbeloro plat_fill_mc(pnode_t nodeid)
550920Sjbeloro {
551920Sjbeloro 	int		portid;
552920Sjbeloro 
553920Sjbeloro 	/*
554920Sjbeloro 	 * Memory controller portid == global CPU id
555920Sjbeloro 	 */
556920Sjbeloro 	if ((prom_getprop(nodeid, "portid", (caddr_t)&portid) == -1) ||
557920Sjbeloro 	    (portid < 0))
558920Sjbeloro 		return;
559920Sjbeloro 
560920Sjbeloro 	if (portid < max_mem_nodes)
561920Sjbeloro 		plat_assign_lgrphand_to_mem_node((lgrp_handle_t)portid, portid);
562920Sjbeloro }
563920Sjbeloro 
564920Sjbeloro 
565920Sjbeloro /*
566920Sjbeloro  * Common locking enter code
567920Sjbeloro  */
568920Sjbeloro void
plat_setprop_enter(void)569920Sjbeloro plat_setprop_enter(void)
570920Sjbeloro {
571920Sjbeloro 	mutex_enter(&mi2cv_mutex);
572920Sjbeloro }
573920Sjbeloro 
574920Sjbeloro /*
575920Sjbeloro  * Common locking exit code
576920Sjbeloro  */
577920Sjbeloro void
plat_setprop_exit(void)578920Sjbeloro plat_setprop_exit(void)
579920Sjbeloro {
580920Sjbeloro 	mutex_exit(&mi2cv_mutex);
581920Sjbeloro }
582920Sjbeloro 
583920Sjbeloro /*
584920Sjbeloro  * Called by mi2cv driver
585920Sjbeloro  */
586920Sjbeloro void
plat_shared_i2c_enter(dev_info_t * i2cnexus_dip)587920Sjbeloro plat_shared_i2c_enter(dev_info_t *i2cnexus_dip)
588920Sjbeloro {
589920Sjbeloro 	if (i2cnexus_dip == shared_mi2cv_dip) {
590920Sjbeloro 		plat_setprop_enter();
591920Sjbeloro 	}
592920Sjbeloro }
593920Sjbeloro 
594920Sjbeloro /*
595920Sjbeloro  * Called by mi2cv driver
596920Sjbeloro  */
597920Sjbeloro void
plat_shared_i2c_exit(dev_info_t * i2cnexus_dip)598920Sjbeloro plat_shared_i2c_exit(dev_info_t *i2cnexus_dip)
599920Sjbeloro {
600920Sjbeloro 	if (i2cnexus_dip == shared_mi2cv_dip) {
601920Sjbeloro 		plat_setprop_exit();
602920Sjbeloro 	}
603920Sjbeloro }
604920Sjbeloro 
605920Sjbeloro /*
606920Sjbeloro  * Called by todm5823 driver
607920Sjbeloro  */
608920Sjbeloro void
plat_rmc_comm_req(struct rmc_comm_msg * request)609920Sjbeloro plat_rmc_comm_req(struct rmc_comm_msg *request)
610920Sjbeloro {
611920Sjbeloro 	if (rmc_req_now)
612920Sjbeloro 		(void) rmc_req_now(request, 0);
613920Sjbeloro }
614