11ae08745Sheppo /*
21ae08745Sheppo  * CDDL HEADER START
31ae08745Sheppo  *
41ae08745Sheppo  * The contents of this file are subject to the terms of the
51ae08745Sheppo  * Common Development and Distribution License (the "License").
61ae08745Sheppo  * You may not use this file except in compliance with the License.
71ae08745Sheppo  *
81ae08745Sheppo  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91ae08745Sheppo  * or http://www.opensolaris.org/os/licensing.
101ae08745Sheppo  * See the License for the specific language governing permissions
111ae08745Sheppo  * and limitations under the License.
121ae08745Sheppo  *
131ae08745Sheppo  * When distributing Covered Code, include this CDDL HEADER in each
141ae08745Sheppo  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151ae08745Sheppo  * If applicable, add the following below this CDDL HEADER, with the
161ae08745Sheppo  * fields enclosed by brackets "[]" replaced with your own identifying
171ae08745Sheppo  * information: Portions Copyright [yyyy] [name of copyright owner]
181ae08745Sheppo  *
191ae08745Sheppo  * CDDL HEADER END
201ae08745Sheppo  */
211ae08745Sheppo 
221ae08745Sheppo /*
23*b5353d91SAbhinandan Ekande  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
241ae08745Sheppo  * Use is subject to license terms.
251ae08745Sheppo  */
261ae08745Sheppo 
271ae08745Sheppo #include <sys/types.h>
281ae08745Sheppo #include <sys/esunddi.h>
291ae08745Sheppo #include <sys/promif_impl.h>
301ae08745Sheppo 
311ae08745Sheppo #ifdef _KMDB
321ae08745Sheppo static pnode_t chosennode;
331ae08745Sheppo static pnode_t optionsnode;
341ae08745Sheppo #else
351ae08745Sheppo static char *gettoken(char *tp, char *token);
361ae08745Sheppo static pnode_t finddevice(char *path);
371ae08745Sheppo #endif
381ae08745Sheppo 
391ae08745Sheppo /*
401ae08745Sheppo  * Routines for walking the PROMs devinfo tree
411ae08745Sheppo  */
421ae08745Sheppo 
431ae08745Sheppo #ifdef _KMDB
441ae08745Sheppo 
451ae08745Sheppo void
promif_set_nodes(pnode_t chosen,pnode_t options)461ae08745Sheppo promif_set_nodes(pnode_t chosen, pnode_t options)
471ae08745Sheppo {
481ae08745Sheppo 	chosennode = chosen;
491ae08745Sheppo 	optionsnode = options;
501ae08745Sheppo }
511ae08745Sheppo 
521ae08745Sheppo int
promif_finddevice(void * p)531ae08745Sheppo promif_finddevice(void *p)
541ae08745Sheppo {
551ae08745Sheppo 	cell_t	*ci = (cell_t *)p;
561ae08745Sheppo 	char *path;
571ae08745Sheppo 
581ae08745Sheppo 	ASSERT(ci[1] == 1);
591ae08745Sheppo 
601ae08745Sheppo 	path = p1275_cell2ptr(ci[3]);
611ae08745Sheppo 
621ae08745Sheppo 	if (strcmp("/chosen", path) == 0) {
631ae08745Sheppo 		ci[4] = p1275_dnode2cell(chosennode);
641ae08745Sheppo 	} else if (strcmp("/options", path) == 0) {
651ae08745Sheppo 		ci[4] = p1275_dnode2cell(optionsnode);
661ae08745Sheppo 	} else {
671ae08745Sheppo 		/* only supports known nodes */
681ae08745Sheppo 		ASSERT(0);
691ae08745Sheppo 	}
701ae08745Sheppo 
711ae08745Sheppo 	return (0);
721ae08745Sheppo }
731ae08745Sheppo 
741ae08745Sheppo #else
751ae08745Sheppo 
761ae08745Sheppo int
promif_finddevice(void * p)771ae08745Sheppo promif_finddevice(void *p)
781ae08745Sheppo {
791ae08745Sheppo 	cell_t	*ci = (cell_t *)p;
801ae08745Sheppo 	pnode_t	node;
811ae08745Sheppo 
821ae08745Sheppo 	ASSERT(ci[1] == 1);
831ae08745Sheppo 
84*b5353d91SAbhinandan Ekande 	/*
85*b5353d91SAbhinandan Ekande 	 * We are passing the cpu pointer (CPU->cpu_id) explicitly to
86*b5353d91SAbhinandan Ekande 	 * thread_affinity_set() so that we don't attempt to grab the
87*b5353d91SAbhinandan Ekande 	 * cpu_lock internally in thread_affinity_set() and may sleep
88*b5353d91SAbhinandan Ekande 	 * as a result.
89*b5353d91SAbhinandan Ekande 	 * It is safe to pass CPU->cpu_id and it will always be valid.
90*b5353d91SAbhinandan Ekande 	 */
91*b5353d91SAbhinandan Ekande 	thread_affinity_set(curthread, CPU->cpu_id);
921ae08745Sheppo 	node = finddevice(p1275_cell2ptr(ci[3]));
931ae08745Sheppo 
941ae08745Sheppo 	ci[4] = p1275_dnode2cell(node);
95*b5353d91SAbhinandan Ekande 	thread_affinity_clear(curthread);
961ae08745Sheppo 
971ae08745Sheppo 	return (0);
981ae08745Sheppo }
991ae08745Sheppo 
1001ae08745Sheppo #endif
1011ae08745Sheppo 
1021ae08745Sheppo int
promif_nextnode(void * p)1031ae08745Sheppo promif_nextnode(void *p)
1041ae08745Sheppo {
1051ae08745Sheppo 	cell_t	*ci = (cell_t *)p;
1061ae08745Sheppo 	pnode_t	next;
1071ae08745Sheppo 
1081ae08745Sheppo 	ASSERT(ci[1] == 1);
1091ae08745Sheppo 
1101ae08745Sheppo 	next = promif_stree_nextnode(p1275_cell2dnode(ci[3]));
1111ae08745Sheppo 
1121ae08745Sheppo 	ci[4] = p1275_dnode2cell(next);
1131ae08745Sheppo 
1141ae08745Sheppo 	return (0);
1151ae08745Sheppo }
1161ae08745Sheppo 
1171ae08745Sheppo int
promif_childnode(void * p)1181ae08745Sheppo promif_childnode(void *p)
1191ae08745Sheppo {
1201ae08745Sheppo 	cell_t	*ci = (cell_t *)p;
1211ae08745Sheppo 	pnode_t	child;
1221ae08745Sheppo 
1231ae08745Sheppo 	ASSERT(ci[1] == 1);
1241ae08745Sheppo 
1251ae08745Sheppo 	child = promif_stree_childnode(p1275_cell2dnode(ci[3]));
1261ae08745Sheppo 
1271ae08745Sheppo 	ci[4] = p1275_dnode2cell(child);
1281ae08745Sheppo 
1291ae08745Sheppo 	return (0);
1301ae08745Sheppo }
1311ae08745Sheppo 
1321ae08745Sheppo int
promif_parentnode(void * p)1331ae08745Sheppo promif_parentnode(void *p)
1341ae08745Sheppo {
1351ae08745Sheppo 	cell_t	*ci = (cell_t *)p;
1361ae08745Sheppo 	pnode_t	parent;
1371ae08745Sheppo 
1381ae08745Sheppo 	ASSERT(ci[1] == 1);
1391ae08745Sheppo 
1401ae08745Sheppo 	parent = promif_stree_parentnode(p1275_cell2dnode(ci[3]));
1411ae08745Sheppo 
1421ae08745Sheppo 	ci[4] = p1275_dnode2cell(parent);
1431ae08745Sheppo 
1441ae08745Sheppo 	return (0);
1451ae08745Sheppo }
1461ae08745Sheppo 
1471ae08745Sheppo #ifndef _KMDB
1481ae08745Sheppo 
1491ae08745Sheppo /*
1501ae08745Sheppo  * Get a token from a prom pathname, collecting everything
1511ae08745Sheppo  * until a non-comma, non-colon separator is found. Any
1521ae08745Sheppo  * options, including the ':' option separator, on the end
1531ae08745Sheppo  * of the token are removed.
1541ae08745Sheppo  */
1551ae08745Sheppo static char *
gettoken(char * tp,char * token)1561ae08745Sheppo gettoken(char *tp, char *token)
1571ae08745Sheppo {
1581ae08745Sheppo 	char *result = token;
1591ae08745Sheppo 
1601ae08745Sheppo 	for (;;) {
1611ae08745Sheppo 		tp = prom_path_gettoken(tp, token);
1621ae08745Sheppo 		token += prom_strlen(token);
1631ae08745Sheppo 		if ((*tp == ',') || (*tp == ':')) {
1641ae08745Sheppo 			*token++ = *tp++;
1651ae08745Sheppo 			*token = '\0';
1661ae08745Sheppo 			continue;
1671ae08745Sheppo 		}
1681ae08745Sheppo 		break;
1691ae08745Sheppo 	}
1701ae08745Sheppo 
1711ae08745Sheppo 	/* strip off any options from the token */
1721ae08745Sheppo 	prom_strip_options(result, result);
1731ae08745Sheppo 
1741ae08745Sheppo 	return (tp);
1751ae08745Sheppo }
1761ae08745Sheppo 
1771ae08745Sheppo /*
1781ae08745Sheppo  * Retrieve the unit address for a node by looking it up
1791ae08745Sheppo  * in the corresponding dip. -1 is returned if no unit
1801ae08745Sheppo  * address can be determined.
1811ae08745Sheppo  */
1821ae08745Sheppo static int
get_unit_addr(pnode_t np,char * paddr)1831ae08745Sheppo get_unit_addr(pnode_t np, char *paddr)
1841ae08745Sheppo {
1851ae08745Sheppo 	dev_info_t	*dip;
1861ae08745Sheppo 	char		*addr;
1871ae08745Sheppo 
1881ae08745Sheppo 	if ((dip = e_ddi_nodeid_to_dip(np)) == NULL) {
1891ae08745Sheppo 		return (-1);
1901ae08745Sheppo 	}
1911ae08745Sheppo 
1921ae08745Sheppo 	if ((addr = ddi_get_name_addr(dip)) == NULL) {
1931ae08745Sheppo 		ddi_release_devi(dip);
1941ae08745Sheppo 		return (-1);
1951ae08745Sheppo 	}
1961ae08745Sheppo 
1971ae08745Sheppo 	(void) prom_strcpy(paddr, addr);
1981ae08745Sheppo 
1991ae08745Sheppo 	ddi_release_devi(dip);
2001ae08745Sheppo 
2011ae08745Sheppo 	return (0);
2021ae08745Sheppo }
2031ae08745Sheppo 
2041ae08745Sheppo /*
2051ae08745Sheppo  * Get node id of node in prom tree that path identifies
2061ae08745Sheppo  */
2071ae08745Sheppo static pnode_t
finddevice(char * path)2081ae08745Sheppo finddevice(char *path)
2091ae08745Sheppo {
2101ae08745Sheppo 	char	name[OBP_MAXPROPNAME];
2111ae08745Sheppo 	char	addr[OBP_MAXPROPNAME];
2121ae08745Sheppo 	char	pname[OBP_MAXPROPNAME];
2131ae08745Sheppo 	char	paddr[OBP_MAXPROPNAME];
2141ae08745Sheppo 	char	*tp;
2151ae08745Sheppo 	pnode_t	np;
2161ae08745Sheppo 	pnode_t	device;
2171ae08745Sheppo 
2181ae08745Sheppo 	CIF_DBG_NODE("finddevice: %s\n", path);
2191ae08745Sheppo 
2201ae08745Sheppo 	tp = path;
2211ae08745Sheppo 	np = prom_rootnode();
2221ae08745Sheppo 	device = OBP_BADNODE;
2231ae08745Sheppo 
2241ae08745Sheppo 	/* must be a fully specified path */
2251ae08745Sheppo 	if (*tp++ != '/')
2261ae08745Sheppo 		goto done;
2271ae08745Sheppo 
2281ae08745Sheppo 	for (;;) {
2291ae08745Sheppo 		/* get the name from the path */
2301ae08745Sheppo 		tp = gettoken(tp, name);
2311ae08745Sheppo 		if (*name == '\0')
2321ae08745Sheppo 			break;
2331ae08745Sheppo 
2341ae08745Sheppo 		/* get the address from the path */
2351ae08745Sheppo 		if (*tp == '@') {
2361ae08745Sheppo 			tp++;
2371ae08745Sheppo 			tp = gettoken(tp, addr);
2381ae08745Sheppo 		} else {
2391ae08745Sheppo 			addr[0] = '\0';
2401ae08745Sheppo 		}
2411ae08745Sheppo 
2421ae08745Sheppo 		CIF_DBG_NODE("looking for: %s%s%s\n", name,
2431ae08745Sheppo 		    (*addr != '\0') ? "@" : "", addr);
2441ae08745Sheppo 
2451ae08745Sheppo 		if ((np = prom_childnode(np)) == OBP_NONODE)
2461ae08745Sheppo 			break;
2471ae08745Sheppo 
2481ae08745Sheppo 		while (np != OBP_NONODE) {
2491ae08745Sheppo 
2501ae08745Sheppo 			/* get the name from the current node */
2511ae08745Sheppo 			if (prom_getprop(np, OBP_NAME, pname) < 0)
2521ae08745Sheppo 				goto done;
2531ae08745Sheppo 
2541ae08745Sheppo 			/* get the address from the current node */
2551ae08745Sheppo 			if (get_unit_addr(np, paddr) < 0)
2561ae08745Sheppo 				paddr[0] = '\0';
2571ae08745Sheppo 
2581ae08745Sheppo 			/* compare the names and addresses */
2591ae08745Sheppo 			if ((prom_strcmp(name, pname) == 0) &&
2601ae08745Sheppo 			    (prom_strcmp(addr, paddr) == 0)) {
2611ae08745Sheppo 				CIF_DBG_NODE("found dev: %s%s%s (0x%x)\n",
2621ae08745Sheppo 				    pname, (*paddr != '\0') ? "@" : "",
2631ae08745Sheppo 				    paddr, np);
2641ae08745Sheppo 				break;
2651ae08745Sheppo 			} else {
2661ae08745Sheppo 				CIF_DBG_NODE("  no match: %s%s%s vs %s%s%s\n",
2671ae08745Sheppo 				    name, (*addr != '\0') ? "@" : "", addr,
2681ae08745Sheppo 				    pname, (*paddr != '\0') ? "@" : "", paddr);
2691ae08745Sheppo 			}
2701ae08745Sheppo 			np = prom_nextnode(np);
2711ae08745Sheppo 		}
2721ae08745Sheppo 
2731ae08745Sheppo 		/* path does not map to a node */
2741ae08745Sheppo 		if (np == OBP_NONODE)
2751ae08745Sheppo 			break;
2761ae08745Sheppo 
2771ae08745Sheppo 		if (*tp == '\0') {
2781ae08745Sheppo 			/* found a matching node */
2791ae08745Sheppo 			device = np;
2801ae08745Sheppo 			break;
2811ae08745Sheppo 		}
2821ae08745Sheppo 
2831ae08745Sheppo 		/*
2841ae08745Sheppo 		 * Continue the loop with the
2851ae08745Sheppo 		 * next component of the path.
2861ae08745Sheppo 		 */
2871ae08745Sheppo 		tp++;
2881ae08745Sheppo 	}
2891ae08745Sheppo done:
2901ae08745Sheppo 
2911ae08745Sheppo 	if (device == OBP_BADNODE) {
2921ae08745Sheppo 		CIF_DBG_NODE("device not found\n\n");
2931ae08745Sheppo 	} else {
2941ae08745Sheppo 		CIF_DBG_NODE("returning 0x%x\n\n", device);
2951ae08745Sheppo 	}
2961ae08745Sheppo 
2971ae08745Sheppo 	return (device);
2981ae08745Sheppo }
2991ae08745Sheppo 
3001ae08745Sheppo #endif
301