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