/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include <sys/types.h> #include <sys/esunddi.h> #include <sys/promif_impl.h> #ifdef _KMDB static pnode_t chosennode; static pnode_t optionsnode; #else static char *gettoken(char *tp, char *token); static pnode_t finddevice(char *path); #endif /* * Routines for walking the PROMs devinfo tree */ #ifdef _KMDB void promif_set_nodes(pnode_t chosen, pnode_t options) { chosennode = chosen; optionsnode = options; } int promif_finddevice(void *p) { cell_t *ci = (cell_t *)p; char *path; ASSERT(ci[1] == 1); path = p1275_cell2ptr(ci[3]); if (strcmp("/chosen", path) == 0) { ci[4] = p1275_dnode2cell(chosennode); } else if (strcmp("/options", path) == 0) { ci[4] = p1275_dnode2cell(optionsnode); } else { /* only supports known nodes */ ASSERT(0); } return (0); } #else int promif_finddevice(void *p) { cell_t *ci = (cell_t *)p; pnode_t node; ASSERT(ci[1] == 1); /* * We are passing the cpu pointer (CPU->cpu_id) explicitly to * thread_affinity_set() so that we don't attempt to grab the * cpu_lock internally in thread_affinity_set() and may sleep * as a result. * It is safe to pass CPU->cpu_id and it will always be valid. */ thread_affinity_set(curthread, CPU->cpu_id); node = finddevice(p1275_cell2ptr(ci[3])); ci[4] = p1275_dnode2cell(node); thread_affinity_clear(curthread); return (0); } #endif int promif_nextnode(void *p) { cell_t *ci = (cell_t *)p; pnode_t next; ASSERT(ci[1] == 1); next = promif_stree_nextnode(p1275_cell2dnode(ci[3])); ci[4] = p1275_dnode2cell(next); return (0); } int promif_childnode(void *p) { cell_t *ci = (cell_t *)p; pnode_t child; ASSERT(ci[1] == 1); child = promif_stree_childnode(p1275_cell2dnode(ci[3])); ci[4] = p1275_dnode2cell(child); return (0); } int promif_parentnode(void *p) { cell_t *ci = (cell_t *)p; pnode_t parent; ASSERT(ci[1] == 1); parent = promif_stree_parentnode(p1275_cell2dnode(ci[3])); ci[4] = p1275_dnode2cell(parent); return (0); } #ifndef _KMDB /* * Get a token from a prom pathname, collecting everything * until a non-comma, non-colon separator is found. Any * options, including the ':' option separator, on the end * of the token are removed. */ static char * gettoken(char *tp, char *token) { char *result = token; for (;;) { tp = prom_path_gettoken(tp, token); token += prom_strlen(token); if ((*tp == ',') || (*tp == ':')) { *token++ = *tp++; *token = '\0'; continue; } break; } /* strip off any options from the token */ prom_strip_options(result, result); return (tp); } /* * Retrieve the unit address for a node by looking it up * in the corresponding dip. -1 is returned if no unit * address can be determined. */ static int get_unit_addr(pnode_t np, char *paddr) { dev_info_t *dip; char *addr; if ((dip = e_ddi_nodeid_to_dip(np)) == NULL) { return (-1); } if ((addr = ddi_get_name_addr(dip)) == NULL) { ddi_release_devi(dip); return (-1); } (void) prom_strcpy(paddr, addr); ddi_release_devi(dip); return (0); } /* * Get node id of node in prom tree that path identifies */ static pnode_t finddevice(char *path) { char name[OBP_MAXPROPNAME]; char addr[OBP_MAXPROPNAME]; char pname[OBP_MAXPROPNAME]; char paddr[OBP_MAXPROPNAME]; char *tp; pnode_t np; pnode_t device; CIF_DBG_NODE("finddevice: %s\n", path); tp = path; np = prom_rootnode(); device = OBP_BADNODE; /* must be a fully specified path */ if (*tp++ != '/') goto done; for (;;) { /* get the name from the path */ tp = gettoken(tp, name); if (*name == '\0') break; /* get the address from the path */ if (*tp == '@') { tp++; tp = gettoken(tp, addr); } else { addr[0] = '\0'; } CIF_DBG_NODE("looking for: %s%s%s\n", name, (*addr != '\0') ? "@" : "", addr); if ((np = prom_childnode(np)) == OBP_NONODE) break; while (np != OBP_NONODE) { /* get the name from the current node */ if (prom_getprop(np, OBP_NAME, pname) < 0) goto done; /* get the address from the current node */ if (get_unit_addr(np, paddr) < 0) paddr[0] = '\0'; /* compare the names and addresses */ if ((prom_strcmp(name, pname) == 0) && (prom_strcmp(addr, paddr) == 0)) { CIF_DBG_NODE("found dev: %s%s%s (0x%x)\n", pname, (*paddr != '\0') ? "@" : "", paddr, np); break; } else { CIF_DBG_NODE(" no match: %s%s%s vs %s%s%s\n", name, (*addr != '\0') ? "@" : "", addr, pname, (*paddr != '\0') ? "@" : "", paddr); } np = prom_nextnode(np); } /* path does not map to a node */ if (np == OBP_NONODE) break; if (*tp == '\0') { /* found a matching node */ device = np; break; } /* * Continue the loop with the * next component of the path. */ tp++; } done: if (device == OBP_BADNODE) { CIF_DBG_NODE("device not found\n\n"); } else { CIF_DBG_NODE("returning 0x%x\n\n", device); } return (device); } #endif