xref: /illumos-gate/usr/src/uts/sun4u/serengeti/io/sbdp.c (revision 07d06da5)
103831d35Sstevel /*
203831d35Sstevel  * CDDL HEADER START
303831d35Sstevel  *
403831d35Sstevel  * The contents of this file are subject to the terms of the
503831d35Sstevel  * Common Development and Distribution License (the "License").
603831d35Sstevel  * You may not use this file except in compliance with the License.
703831d35Sstevel  *
803831d35Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
903831d35Sstevel  * or http://www.opensolaris.org/os/licensing.
1003831d35Sstevel  * See the License for the specific language governing permissions
1103831d35Sstevel  * and limitations under the License.
1203831d35Sstevel  *
1303831d35Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
1403831d35Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1503831d35Sstevel  * If applicable, add the following below this CDDL HEADER, with the
1603831d35Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
1703831d35Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
1803831d35Sstevel  *
1903831d35Sstevel  * CDDL HEADER END
2003831d35Sstevel  */
2103831d35Sstevel 
2203831d35Sstevel /*
23*07d06da5SSurya Prakki  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2403831d35Sstevel  * Use is subject to license terms.
2503831d35Sstevel  */
2603831d35Sstevel 
2703831d35Sstevel #include <sys/types.h>
2803831d35Sstevel #include <sys/cmn_err.h>
2903831d35Sstevel #include <sys/conf.h>
3003831d35Sstevel #include <sys/ddi_impldefs.h>
3103831d35Sstevel #include <sys/autoconf.h>
3203831d35Sstevel #include <sys/systm.h>
3303831d35Sstevel #include <sys/modctl.h>
3403831d35Sstevel #include <sys/ddi.h>
3503831d35Sstevel #include <sys/sunddi.h>
3603831d35Sstevel #include <sys/sunndi.h>
3703831d35Sstevel #include <sys/ndi_impldefs.h>
3803831d35Sstevel #include <sys/promif.h>
3903831d35Sstevel #include <sys/stat.h>
4003831d35Sstevel #include <sys/kmem.h>
4103831d35Sstevel #include <sys/promif.h>
4203831d35Sstevel #include <sys/conf.h>
4303831d35Sstevel #include <sys/obpdefs.h>
4403831d35Sstevel #include <sys/cpuvar.h>
4503831d35Sstevel #include <vm/seg_kmem.h>
4603831d35Sstevel #include <sys/prom_plat.h>
4703831d35Sstevel #include <sys/machsystm.h>
4803831d35Sstevel #include <sys/note.h>
4903831d35Sstevel #include <sys/memlist.h>
5003831d35Sstevel #include <sys/ssm.h>
5103831d35Sstevel 
5203831d35Sstevel #include <sys/sbd_ioctl.h>
5303831d35Sstevel #include <sys/sbd.h>
5403831d35Sstevel #include <sys/sbdp_priv.h>
5503831d35Sstevel #include <sys/sbdp_mem.h>
5603831d35Sstevel #include <sys/sbdp_error.h>
5703831d35Sstevel #include <sys/serengeti.h>
5803831d35Sstevel 
5903831d35Sstevel #include <sys/sgsbbc.h>		/* To get fn_t type definition */
6003831d35Sstevel 
6103831d35Sstevel /*
6203831d35Sstevel  * Config information
6303831d35Sstevel  */
6403831d35Sstevel #ifdef DEBUG
6503831d35Sstevel uint_t sbdp_debug = 0x0;
6603831d35Sstevel #endif /* DEBUG */
6703831d35Sstevel 
6803831d35Sstevel /*
6903831d35Sstevel  * Enable or disable dr
7003831d35Sstevel  */
7103831d35Sstevel int sbdp_dr_available = 1;
7203831d35Sstevel 
7303831d35Sstevel /* name properties for some Serengeti device nodes */
7403831d35Sstevel #define	CMP_DEVNAME		"cmp"
7503831d35Sstevel #define	MEM_DEVNAME		"memory"
7603831d35Sstevel #define	CPU_DEVNAME		"cpu"
7703831d35Sstevel #define	IO_PCI_DEVNAME		"pci"
7803831d35Sstevel #define	IO_SGHSC_DEVNAME	"sghsc"
7903831d35Sstevel #define	IO_WCI_DEVNAME		"wci"
8003831d35Sstevel 
8103831d35Sstevel static	sbd_devattr_t	sbdp_devattr[] = {
8203831d35Sstevel 	{ CMP_DEVNAME,		"cmp",			SBD_COMP_CMP },
8303831d35Sstevel 	{ MEM_DEVNAME,		"memory-controller",	SBD_COMP_MEM },
8403831d35Sstevel 	{ CPU_DEVNAME,		"cpu",			SBD_COMP_CPU },
8503831d35Sstevel 	{ IO_PCI_DEVNAME,	"pci",			SBD_COMP_IO },
8603831d35Sstevel 	{ IO_SGHSC_DEVNAME,	"sghsc",		SBD_COMP_IO },
8703831d35Sstevel 	{ IO_WCI_DEVNAME,	"wci",			SBD_COMP_IO },
8803831d35Sstevel 	/* last item must be blank */
8903831d35Sstevel 	{ NULL,			NULL,			SBD_COMP_UNKNOWN }
9003831d35Sstevel };
9103831d35Sstevel 
9203831d35Sstevel /*
9303831d35Sstevel  * In the case of a busy mbox, if a status cmd comes in we return a cached
9403831d35Sstevel  * copy.  This cache is a link list of wnodes that contains bd structs with
9503831d35Sstevel  * the appropriate info.  When a new wnode is created a whole entry is added
9603831d35Sstevel  * to the list.
9703831d35Sstevel  */
9803831d35Sstevel sbdp_wnode_t	*first_node = NULL; /* first wnode. Entry to the link list */
9903831d35Sstevel int		cur_num_wnodes = 0; /* how many nodes are currently running */
10003831d35Sstevel 
10103831d35Sstevel /* Macros to access fields in the previous array */
10203831d35Sstevel #define	SBDP_CT(i)		sbdp_devattr[i].s_dnodetype
10303831d35Sstevel #define	SBDP_DEVNAME(i)		sbdp_devattr[(i)].s_devname
10403831d35Sstevel #define	SBDP_OTYPE(i)		sbdp_devattr[(i)].s_obp_type
10503831d35Sstevel 
10603831d35Sstevel /*
10703831d35Sstevel  * Prototypes
10803831d35Sstevel  */
10903831d35Sstevel sbdp_wnode_t *sbdp_get_wnodep(int);
11003831d35Sstevel 
11103831d35Sstevel /*
11203831d35Sstevel  * Module linkage information for the kernel.
11303831d35Sstevel  */
11403831d35Sstevel 
11503831d35Sstevel static struct modlmisc modlmisc = {
11603831d35Sstevel 	&mod_miscops,
11703831d35Sstevel 	"Serengeti sbdp",
11803831d35Sstevel };
11903831d35Sstevel 
12003831d35Sstevel static struct modlinkage modlinkage = {
12103831d35Sstevel 	MODREV_1,
12203831d35Sstevel 	(void *)&modlmisc,
12303831d35Sstevel 	NULL
12403831d35Sstevel };
12503831d35Sstevel 
12603831d35Sstevel /*
12703831d35Sstevel  * VA area used during CPU shutdown.
12803831d35Sstevel  */
12903831d35Sstevel caddr_t	sbdp_shutdown_va;
13003831d35Sstevel 
13103831d35Sstevel /*
13203831d35Sstevel  * Mutex to protect our inventory
13303831d35Sstevel  */
13403831d35Sstevel kmutex_t	sbdp_wnode_mutex;
13503831d35Sstevel 
13603831d35Sstevel int
_init(void)13703831d35Sstevel _init(void)
13803831d35Sstevel {
13903831d35Sstevel 	int e;
14003831d35Sstevel 
14103831d35Sstevel 	e = mod_install(&modlinkage);
14203831d35Sstevel 	if (e != 0)
14303831d35Sstevel 		return (e);
14403831d35Sstevel 
14503831d35Sstevel 	sbdp_shutdown_va = vmem_alloc(heap_arena, PAGESIZE, VM_SLEEP);
14603831d35Sstevel 	ASSERT(sbdp_shutdown_va != NULL);
14703831d35Sstevel 	sbdp_valp = (uint64_t *)vmem_alloc(static_alloc_arena,
14803831d35Sstevel 	    sizeof (uint64_t), VM_SLEEP);
14903831d35Sstevel 
15003831d35Sstevel 	mutex_init(&sbdp_wnode_mutex, NULL, MUTEX_DRIVER, NULL);
15103831d35Sstevel 	return (e);
15203831d35Sstevel }
15303831d35Sstevel 
15403831d35Sstevel int
_fini(void)15503831d35Sstevel _fini(void)
15603831d35Sstevel {
15703831d35Sstevel 	int e;
15803831d35Sstevel 
15903831d35Sstevel 	/*
16003831d35Sstevel 	 * Remove the module.
16103831d35Sstevel 	 */
16203831d35Sstevel 	e = mod_remove(&modlinkage);
16303831d35Sstevel 	if (e != 0)
16403831d35Sstevel 		return (e);
16503831d35Sstevel 
16603831d35Sstevel 	vmem_free(heap_arena, sbdp_shutdown_va, PAGESIZE);
16703831d35Sstevel 	sbdp_shutdown_va = NULL;
16803831d35Sstevel 	vmem_free(static_alloc_arena, (void *)sbdp_valp, sizeof (uint64_t));
16903831d35Sstevel 	sbdp_valp = NULL;
17003831d35Sstevel 
17103831d35Sstevel 	mutex_destroy(&sbdp_wnode_mutex);
17203831d35Sstevel 	return (e);
17303831d35Sstevel }
17403831d35Sstevel 
17503831d35Sstevel int
_info(struct modinfo * modinfop)17603831d35Sstevel _info(struct modinfo *modinfop)
17703831d35Sstevel {
17803831d35Sstevel 	return (mod_info(&modlinkage, modinfop));
17903831d35Sstevel }
18003831d35Sstevel 
18103831d35Sstevel int
sbdp_get_bd_and_wnode_num(pnode_t nodeid,int * bd,int * wnode)18203831d35Sstevel sbdp_get_bd_and_wnode_num(pnode_t nodeid, int *bd, int *wnode)
18303831d35Sstevel {
18403831d35Sstevel 	int portid;
18503831d35Sstevel 	static fn_t	f = "sbdp_get_bd_and_wnode_num";
18603831d35Sstevel 	extern int	get_portid(pnode_t node, pnode_t *cmpp);
18703831d35Sstevel 
18803831d35Sstevel 	SBDP_DBG_FUNC("%s\n", f);
18903831d35Sstevel 
19003831d35Sstevel 	if (sbdp_is_node_bad(nodeid))
19103831d35Sstevel 		return (-1);
19203831d35Sstevel 
19303831d35Sstevel 	if ((portid = get_portid(nodeid, NULL)) == -1)
19403831d35Sstevel 		return (-1);
19503831d35Sstevel 
19603831d35Sstevel 	/*
19703831d35Sstevel 	 * decode the board number
19803831d35Sstevel 	 */
19903831d35Sstevel 	*bd = SG_PORTID_TO_BOARD_NUM(portid);
20003831d35Sstevel 	*wnode = SG_PORTID_TO_NODEID(portid);
20103831d35Sstevel 
20203831d35Sstevel 	return (0);
20303831d35Sstevel }
20403831d35Sstevel 
20503831d35Sstevel int
sbdp_get_board_num(sbdp_handle_t * hp,dev_info_t * dip)20603831d35Sstevel sbdp_get_board_num(sbdp_handle_t *hp, dev_info_t *dip)
20703831d35Sstevel {
20803831d35Sstevel 	_NOTE(ARGUNUSED(hp))
20903831d35Sstevel 
21003831d35Sstevel 	pnode_t		nodeid;
21103831d35Sstevel 	int		bd, wnode;
21203831d35Sstevel 	static fn_t	f = "sbdp_get_board_num";
21303831d35Sstevel 
21403831d35Sstevel 	SBDP_DBG_FUNC("%s\n", f);
21503831d35Sstevel 
21603831d35Sstevel 	if (dip == NULL)
21703831d35Sstevel 		return (-1);
21803831d35Sstevel 
21903831d35Sstevel 	nodeid = ddi_get_nodeid(dip);
22003831d35Sstevel 
22103831d35Sstevel 	/*
22203831d35Sstevel 	 * Portid has encoded the nodeid and the agent id.  The top
22303831d35Sstevel 	 * 4 bits are correspond to the wcnodeid and the lower 5 are the
22403831d35Sstevel 	 * agent id.
22503831d35Sstevel 	 * Each agent id represents a physical location hence we can
22603831d35Sstevel 	 * obtain the board number
22703831d35Sstevel 	 */
22803831d35Sstevel 	if (sbdp_get_bd_and_wnode_num(nodeid, &bd, &wnode) < 0)
22903831d35Sstevel 		return (-1);
23003831d35Sstevel 
23103831d35Sstevel 	return (bd);
23203831d35Sstevel }
23303831d35Sstevel 
23403831d35Sstevel 
23503831d35Sstevel sbd_devattr_t *
sbdp_get_devattr(void)23603831d35Sstevel sbdp_get_devattr(void)
23703831d35Sstevel {
23803831d35Sstevel 	return (&sbdp_devattr[0]);
23903831d35Sstevel }
24003831d35Sstevel 
24103831d35Sstevel int
sbdp_portid_to_cpu_unit(int cmp,int core)24203831d35Sstevel sbdp_portid_to_cpu_unit(int cmp, int core)
24303831d35Sstevel {
24403831d35Sstevel 	return (SG_PORTID_TO_CPU_UNIT(cmp, core));
24503831d35Sstevel }
24603831d35Sstevel 
24703831d35Sstevel int
sbdp_get_unit_num(sbdp_handle_t * hp,dev_info_t * dip)24803831d35Sstevel sbdp_get_unit_num(sbdp_handle_t *hp, dev_info_t *dip)
24903831d35Sstevel {
25003831d35Sstevel 	int		unit = -1;
25103831d35Sstevel 	int		portid;
25203831d35Sstevel 	processorid_t	cpuid;
25303831d35Sstevel 	sbd_comp_type_t	type;
25403831d35Sstevel 	char		dev_type[OBP_MAXPROPNAME];
25503831d35Sstevel 	int		i;
25603831d35Sstevel 	pnode_t		nodeid;
25703831d35Sstevel 	static fn_t	f = "sbdp_get_unit_num";
25803831d35Sstevel 
25903831d35Sstevel 	SBDP_DBG_FUNC("%s\n", f);
26003831d35Sstevel 
26103831d35Sstevel 	if (dip == NULL)
26203831d35Sstevel 		return (-1);
26303831d35Sstevel 
26403831d35Sstevel 	nodeid = ddi_get_nodeid(dip);
26503831d35Sstevel 
26603831d35Sstevel 	if (sbdp_is_node_bad(nodeid))
26703831d35Sstevel 		return (-1);
26803831d35Sstevel 
26903831d35Sstevel 	if (prom_getprop(nodeid, "device_type", (caddr_t)dev_type) < 0) {
27003831d35Sstevel 		SBDP_DBG_MISC("%s: couldn't get device_type\n", f);
27103831d35Sstevel 		return (-1);
27203831d35Sstevel 	}
27303831d35Sstevel 
27403831d35Sstevel 	for (i = 0; SBDP_CT(i) != SBD_COMP_UNKNOWN; i++) {
275