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