167204Sobrien/* $NetBSD: Locore.c,v 1.7 2000/08/20 07:04:59 tsubai Exp $ */ 267204Sobrien 3139749Simp/*- 467204Sobrien * Copyright (C) 1995, 1996 Wolfgang Solfrank. 567204Sobrien * Copyright (C) 1995, 1996 TooLs GmbH. 667204Sobrien * All rights reserved. 767204Sobrien * 867204Sobrien * Redistribution and use in source and binary forms, with or without 967204Sobrien * modification, are permitted provided that the following conditions 1067204Sobrien * are met: 1167204Sobrien * 1. Redistributions of source code must retain the above copyright 1267204Sobrien * notice, this list of conditions and the following disclaimer. 1367204Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1467204Sobrien * notice, this list of conditions and the following disclaimer in the 1567204Sobrien * documentation and/or other materials provided with the distribution. 1667204Sobrien * 3. All advertising materials mentioning features or use of this software 1767204Sobrien * must display the following acknowledgement: 1867204Sobrien * This product includes software developed by TooLs GmbH. 1967204Sobrien * 4. The name of TooLs GmbH may not be used to endorse or promote products 2067204Sobrien * derived from this software without specific prior written permission. 2167204Sobrien * 2267204Sobrien * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 2367204Sobrien * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2467204Sobrien * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2567204Sobrien * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2667204Sobrien * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 2767204Sobrien * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 2867204Sobrien * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 2967204Sobrien * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 3067204Sobrien * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 3167204Sobrien * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3267204Sobrien */ 33139749Simp/*- 3467204Sobrien * Copyright (C) 2000 Benno Rice. 3567204Sobrien * All rights reserved. 3667204Sobrien * 3767204Sobrien * Redistribution and use in source and binary forms, with or without 3867204Sobrien * modification, are permitted provided that the following conditions 3967204Sobrien * are met: 4067204Sobrien * 1. Redistributions of source code must retain the above copyright 4167204Sobrien * notice, this list of conditions and the following disclaimer. 4267204Sobrien * 2. Redistributions in binary form must reproduce the above copyright 4367204Sobrien * notice, this list of conditions and the following disclaimer in the 4467204Sobrien * documentation and/or other materials provided with the distribution. 4567204Sobrien * 4667204Sobrien * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR 4767204Sobrien * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 4867204Sobrien * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 4967204Sobrien * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 5067204Sobrien * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 5167204Sobrien * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 5267204Sobrien * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 5367204Sobrien * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 5467204Sobrien * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 5567204Sobrien * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 5667204Sobrien */ 5767204Sobrien 58170838Smarius#include <sys/cdefs.h> 59170838Smarius__FBSDID("$FreeBSD$"); 60170838Smarius 61208614Sraj#include "opt_platform.h" 62208614Sraj 6380697Sjake#include <sys/param.h> 6486557Stmm#include <sys/kernel.h> 65273655Sian#include <sys/lock.h> 6686557Stmm#include <sys/malloc.h> 67273655Sian#include <sys/mutex.h> 68273655Sian#include <sys/queue.h> 6978346Sbenno#include <sys/systm.h> 70259255Sandreast#include <sys/endian.h> 7178346Sbenno 7267204Sobrien#include <machine/stdarg.h> 7367204Sobrien 74194138Smarius#include <dev/ofw/ofwvar.h> 7578346Sbenno#include <dev/ofw/openfirm.h> 7668548Sbenno 77186347Snwhitehorn#include "ofw_if.h" 78186347Snwhitehorn 79230631Smariusstatic void OF_putchar(int c, void *arg); 80230631Smarius 81133862SmariusMALLOC_DEFINE(M_OFWPROP, "openfirm", "Open Firmware properties"); 8286557Stmm 8367204Sobrienstatic ihandle_t stdout; 8467204Sobrien 85215049Snwhitehornstatic ofw_def_t *ofw_def_impl = NULL; 86186347Snwhitehornstatic ofw_t ofw_obj; 87186347Snwhitehornstatic struct ofw_kobj ofw_kernel_obj; 88186347Snwhitehornstatic struct kobj_ops ofw_kernel_kops; 89186347Snwhitehorn 90273655Sianstruct xrefinfo { 91273655Sian phandle_t xref; 92273655Sian phandle_t node; 93273655Sian device_t dev; 94273655Sian SLIST_ENTRY(xrefinfo) next_entry; 95273655Sian}; 96273655Sian 97273655Sianstatic SLIST_HEAD(, xrefinfo) xreflist = SLIST_HEAD_INITIALIZER(xreflist); 98273655Sianstatic struct mtx xreflist_lock; 99273655Sianstatic boolean_t xref_init_done; 100273655Sian 101273655Sian#define FIND_BY_XREF 0 102273655Sian#define FIND_BY_NODE 1 103273655Sian#define FIND_BY_DEV 2 104273655Sian 105186347Snwhitehorn/* 106273655Sian * xref-phandle-device lookup helper routines. 107273655Sian * 108273655Sian * As soon as we are able to use malloc(), walk the node tree and build a list 109273655Sian * of info that cross-references node handles, xref handles, and device_t 110273655Sian * instances. This list exists primarily to allow association of a device_t 111273655Sian * with an xref handle, but it is also used to speed up translation between xref 112273655Sian * and node handles. Before malloc() is available we have to recursively search 113273655Sian * the node tree each time we want to translate between a node and xref handle. 114273655Sian * Afterwards we can do the translations by searching this much shorter list. 115273655Sian */ 116273655Sianstatic void 117273655Sianxrefinfo_create(phandle_t node) 118273655Sian{ 119273655Sian struct xrefinfo * xi; 120273655Sian phandle_t child, xref; 121273655Sian 122273655Sian /* 123273655Sian * Recursively descend from parent, looking for nodes with a property 124273655Sian * named either "phandle", "ibm,phandle", or "linux,phandle". For each 125273655Sian * such node found create an entry in the xreflist. 126273655Sian */ 127273655Sian for (child = OF_child(node); child != 0; child = OF_peer(child)) { 128273655Sian xrefinfo_create(child); 129273655Sian if (OF_getencprop(child, "phandle", &xref, sizeof(xref)) == 130273655Sian -1 && OF_getencprop(child, "ibm,phandle", &xref, 131273655Sian sizeof(xref)) == -1 && OF_getencprop(child, 132273655Sian "linux,phandle", &xref, sizeof(xref)) == -1) 133273655Sian continue; 134273655Sian xi = malloc(sizeof(*xi), M_OFWPROP, M_WAITOK | M_ZERO); 135273655Sian xi->node = child; 136273655Sian xi->xref = xref; 137273655Sian SLIST_INSERT_HEAD(&xreflist, xi, next_entry); 138273655Sian } 139273655Sian} 140273655Sian 141273655Sianstatic void 142273655Sianxrefinfo_init(void *unsed) 143273655Sian{ 144273655Sian 145273655Sian /* 146273655Sian * There is no locking during this init because it runs much earlier 147273655Sian * than any of the clients/consumers of the xref list data, but we do 148273655Sian * initialize the mutex that will be used for access later. 149273655Sian */ 150273655Sian mtx_init(&xreflist_lock, "OF xreflist lock", NULL, MTX_DEF); 151273655Sian xrefinfo_create(OF_peer(0)); 152273655Sian xref_init_done = true; 153273655Sian} 154273655SianSYSINIT(xrefinfo, SI_SUB_KMEM, SI_ORDER_ANY, xrefinfo_init, NULL); 155273655Sian 156273655Sianstatic struct xrefinfo * 157283477Sianxrefinfo_find(uintptr_t key, int find_by) 158273655Sian{ 159273655Sian struct xrefinfo *rv, *xi; 160273655Sian 161273655Sian rv = NULL; 162273655Sian mtx_lock(&xreflist_lock); 163273655Sian SLIST_FOREACH(xi, &xreflist, next_entry) { 164283477Sian if ((find_by == FIND_BY_XREF && (phandle_t)key == xi->xref) || 165283477Sian (find_by == FIND_BY_NODE && (phandle_t)key == xi->node) || 166283477Sian (find_by == FIND_BY_DEV && key == (uintptr_t)xi->dev)) { 167273655Sian rv = xi; 168273655Sian break; 169273655Sian } 170273655Sian } 171273655Sian mtx_unlock(&xreflist_lock); 172273655Sian return (rv); 173273655Sian} 174273655Sian 175273655Sianstatic struct xrefinfo * 176273655Sianxrefinfo_add(phandle_t node, phandle_t xref, device_t dev) 177273655Sian{ 178273655Sian struct xrefinfo *xi; 179273655Sian 180273655Sian xi = malloc(sizeof(*xi), M_OFWPROP, M_WAITOK); 181273655Sian xi->node = node; 182273655Sian xi->xref = xref; 183273655Sian xi->dev = dev; 184273655Sian mtx_lock(&xreflist_lock); 185273655Sian SLIST_INSERT_HEAD(&xreflist, xi, next_entry); 186273655Sian mtx_unlock(&xreflist_lock); 187273655Sian return (xi); 188273655Sian} 189273655Sian 190273655Sian/* 191230631Smarius * OFW install routines. Highest priority wins, equal priority also 192186347Snwhitehorn * overrides allowing last-set to win. 193186347Snwhitehorn */ 194186347SnwhitehornSET_DECLARE(ofw_set, ofw_def_t); 195186347Snwhitehorn 196186347Snwhitehornboolean_t 197186347SnwhitehornOF_install(char *name, int prio) 198186347Snwhitehorn{ 199194138Smarius ofw_def_t *ofwp, **ofwpp; 200186347Snwhitehorn static int curr_prio = 0; 201186347Snwhitehorn 202186347Snwhitehorn /* 203194138Smarius * Try and locate the OFW kobj corresponding to the name. 204194138Smarius */ 205186347Snwhitehorn SET_FOREACH(ofwpp, ofw_set) { 206186347Snwhitehorn ofwp = *ofwpp; 207186347Snwhitehorn 208186347Snwhitehorn if (ofwp->name && 209186347Snwhitehorn !strcmp(ofwp->name, name) && 210186347Snwhitehorn prio >= curr_prio) { 211186347Snwhitehorn curr_prio = prio; 212186347Snwhitehorn ofw_def_impl = ofwp; 213186347Snwhitehorn return (TRUE); 214186347Snwhitehorn } 215186347Snwhitehorn } 216186347Snwhitehorn 217186347Snwhitehorn return (FALSE); 218186347Snwhitehorn} 219186347Snwhitehorn 220194138Smarius/* Initializer */ 221208614Srajint 222186347SnwhitehornOF_init(void *cookie) 22367204Sobrien{ 224170838Smarius phandle_t chosen; 225208614Sraj int rv; 22678346Sbenno 227215049Snwhitehorn if (ofw_def_impl == NULL) 228215049Snwhitehorn return (-1); 229215049Snwhitehorn 230186347Snwhitehorn ofw_obj = &ofw_kernel_obj; 231186347Snwhitehorn /* 232186347Snwhitehorn * Take care of compiling the selected class, and 233194138Smarius * then statically initialize the OFW object. 234186347Snwhitehorn */ 235186347Snwhitehorn kobj_class_compile_static(ofw_def_impl, &ofw_kernel_kops); 236227537Smarius kobj_init_static((kobj_t)ofw_obj, ofw_def_impl); 237186347Snwhitehorn 238208614Sraj rv = OFW_INIT(ofw_obj, cookie); 239186347Snwhitehorn 240228201Sjchandra if ((chosen = OF_finddevice("/chosen")) != -1) 241265967Sian if (OF_getencprop(chosen, "stdout", &stdout, 242265967Sian sizeof(stdout)) == -1) 243208614Sraj stdout = -1; 244208614Sraj 245208614Sraj return (rv); 24667204Sobrien} 24767204Sobrien 248230631Smariusstatic void 249230631SmariusOF_putchar(int c, void *arg __unused) 250230631Smarius{ 251230631Smarius char cbuf; 252230631Smarius 253230631Smarius if (c == '\n') { 254230631Smarius cbuf = '\r'; 255230631Smarius OF_write(stdout, &cbuf, 1); 256230631Smarius } 257230631Smarius 258230631Smarius cbuf = c; 259230631Smarius OF_write(stdout, &cbuf, 1); 260230631Smarius} 261230631Smarius 26278346Sbennovoid 26378346SbennoOF_printf(const char *fmt, ...) 26478346Sbenno{ 26578346Sbenno va_list va; 26678346Sbenno 26778346Sbenno va_start(va, fmt); 268230631Smarius (void)kvprintf(fmt, OF_putchar, NULL, 10, va); 26978346Sbenno va_end(va); 27078346Sbenno} 27178346Sbenno 27267204Sobrien/* 27367204Sobrien * Generic functions 27467204Sobrien */ 27567204Sobrien 27667204Sobrien/* Test to see if a service exists. */ 27767204Sobrienint 278186347SnwhitehornOF_test(const char *name) 27967204Sobrien{ 280194138Smarius 281215049Snwhitehorn if (ofw_def_impl == NULL) 282215049Snwhitehorn return (-1); 283215049Snwhitehorn 284186347Snwhitehorn return (OFW_TEST(ofw_obj, name)); 28567204Sobrien} 28667204Sobrien 287115973Sjakeint 288186347SnwhitehornOF_interpret(const char *cmd, int nreturns, ...) 289115973Sjake{ 290115973Sjake va_list ap; 291212477Smarius cell_t slots[16]; 292115973Sjake int i = 0; 293186347Snwhitehorn int status; 294115973Sjake 295215049Snwhitehorn if (ofw_def_impl == NULL) 296215049Snwhitehorn return (-1); 297215049Snwhitehorn 298186347Snwhitehorn status = OFW_INTERPRET(ofw_obj, cmd, nreturns, slots); 299190522Smarius if (status == -1) 300190522Smarius return (status); 301186347Snwhitehorn 302171265Speter va_start(ap, nreturns); 303190522Smarius while (i < nreturns) 304186347Snwhitehorn *va_arg(ap, cell_t *) = slots[i++]; 305115973Sjake va_end(ap); 306186347Snwhitehorn 307115973Sjake return (status); 308115973Sjake} 309115973Sjake 31067204Sobrien/* 31167204Sobrien * Device tree functions 31267204Sobrien */ 31367204Sobrien 31467204Sobrien/* Return the next sibling of this node or 0. */ 31567204Sobrienphandle_t 31667204SobrienOF_peer(phandle_t node) 31767204Sobrien{ 318194138Smarius 319215049Snwhitehorn if (ofw_def_impl == NULL) 320215049Snwhitehorn return (0); 321215049Snwhitehorn 322186347Snwhitehorn return (OFW_PEER(ofw_obj, node)); 32367204Sobrien} 32467204Sobrien 32567204Sobrien/* Return the first child of this node or 0. */ 32667204Sobrienphandle_t 32767204SobrienOF_child(phandle_t node) 32867204Sobrien{ 329194138Smarius 330215049Snwhitehorn if (ofw_def_impl == NULL) 331215049Snwhitehorn return (0); 332215049Snwhitehorn 333186347Snwhitehorn return (OFW_CHILD(ofw_obj, node)); 33467204Sobrien} 33567204Sobrien 33667204Sobrien/* Return the parent of this node or 0. */ 33767204Sobrienphandle_t 33867204SobrienOF_parent(phandle_t node) 33967204Sobrien{ 340194138Smarius 341215049Snwhitehorn if (ofw_def_impl == NULL) 342215049Snwhitehorn return (0); 343215049Snwhitehorn 344186347Snwhitehorn return (OFW_PARENT(ofw_obj, node)); 34567204Sobrien} 34667204Sobrien 34767204Sobrien/* Return the package handle that corresponds to an instance handle. */ 34867204Sobrienphandle_t 34967204SobrienOF_instance_to_package(ihandle_t instance) 35067204Sobrien{ 351194138Smarius 352215049Snwhitehorn if (ofw_def_impl == NULL) 353215049Snwhitehorn return (-1); 354215049Snwhitehorn 355186347Snwhitehorn return (OFW_INSTANCE_TO_PACKAGE(ofw_obj, instance)); 35667204Sobrien} 35767204Sobrien 35867204Sobrien/* Get the length of a property of a package. */ 359186347Snwhitehornssize_t 360186347SnwhitehornOF_getproplen(phandle_t package, const char *propname) 36167204Sobrien{ 362194138Smarius 363215049Snwhitehorn if (ofw_def_impl == NULL) 364215049Snwhitehorn return (-1); 365215049Snwhitehorn 366186347Snwhitehorn return (OFW_GETPROPLEN(ofw_obj, package, propname)); 36767204Sobrien} 36867204Sobrien 369239366Shrs/* Check existence of a property of a package. */ 370239366Shrsint 371239366ShrsOF_hasprop(phandle_t package, const char *propname) 372239366Shrs{ 373239366Shrs 374239366Shrs return (OF_getproplen(package, propname) >= 0 ? 1 : 0); 375239366Shrs} 376239366Shrs 37767204Sobrien/* Get the value of a property of a package. */ 378186347Snwhitehornssize_t 379186347SnwhitehornOF_getprop(phandle_t package, const char *propname, void *buf, size_t buflen) 38067204Sobrien{ 381194138Smarius 382215049Snwhitehorn if (ofw_def_impl == NULL) 383215049Snwhitehorn return (-1); 384215049Snwhitehorn 385186347Snwhitehorn return (OFW_GETPROP(ofw_obj, package, propname, buf, buflen)); 38667204Sobrien} 38767204Sobrien 388259255Sandreastssize_t 389259255SandreastOF_getencprop(phandle_t node, const char *propname, pcell_t *buf, size_t len) 390259255Sandreast{ 391259255Sandreast ssize_t retval; 392259255Sandreast int i; 393259255Sandreast 394259255Sandreast KASSERT(len % 4 == 0, ("Need a multiple of 4 bytes")); 395259255Sandreast 396259255Sandreast retval = OF_getprop(node, propname, buf, len); 397259255Sandreast for (i = 0; i < len/4; i++) 398259255Sandreast buf[i] = be32toh(buf[i]); 399259255Sandreast 400259255Sandreast return (retval); 401259255Sandreast} 402259255Sandreast 40386557Stmm/* 404208614Sraj * Recursively search the node and its parent for the given property, working 405186728Snwhitehorn * downward from the node to the device tree root. Returns the value of the 406186728Snwhitehorn * first match. 407186728Snwhitehorn */ 408186728Snwhitehornssize_t 409194138SmariusOF_searchprop(phandle_t node, const char *propname, void *buf, size_t len) 410186728Snwhitehorn{ 411186728Snwhitehorn ssize_t rv; 412186728Snwhitehorn 413194138Smarius for (; node != 0; node = OF_parent(node)) 414186728Snwhitehorn if ((rv = OF_getprop(node, propname, buf, len)) != -1) 415186728Snwhitehorn return (rv); 416186728Snwhitehorn return (-1); 417186728Snwhitehorn} 418186728Snwhitehorn 419259255Sandreastssize_t 420259255SandreastOF_searchencprop(phandle_t node, const char *propname, void *buf, size_t len) 421259255Sandreast{ 422259255Sandreast ssize_t rv; 423259255Sandreast 424259255Sandreast for (; node != 0; node = OF_parent(node)) 425259255Sandreast if ((rv = OF_getencprop(node, propname, buf, len)) != -1) 426259255Sandreast return (rv); 427259255Sandreast return (-1); 428259255Sandreast} 429259255Sandreast 430186728Snwhitehorn/* 431129588Smarius * Store the value of a property of a package into newly allocated memory 432194138Smarius * (using the M_OFWPROP malloc pool and M_WAITOK). elsz is the size of a 433129588Smarius * single element, the number of elements is return in number. 43486557Stmm */ 435186347Snwhitehornssize_t 436186347SnwhitehornOF_getprop_alloc(phandle_t package, const char *propname, int elsz, void **buf) 43786557Stmm{ 43886557Stmm int len; 43986557Stmm 44086557Stmm *buf = NULL; 44186557Stmm if ((len = OF_getproplen(package, propname)) == -1 || 44286557Stmm len % elsz != 0) 44386557Stmm return (-1); 44486557Stmm 445111119Simp *buf = malloc(len, M_OFWPROP, M_WAITOK); 44686557Stmm if (OF_getprop(package, propname, *buf, len) == -1) { 44786557Stmm free(*buf, M_OFWPROP); 44886557Stmm *buf = NULL; 44986557Stmm return (-1); 45086557Stmm } 45186557Stmm return (len / elsz); 45286557Stmm} 45386557Stmm 454259255Sandreastssize_t 455259255SandreastOF_getencprop_alloc(phandle_t package, const char *name, int elsz, void **buf) 456259255Sandreast{ 457259255Sandreast ssize_t retval; 458259255Sandreast pcell_t *cell; 459259255Sandreast int i; 460259255Sandreast 461259255Sandreast retval = OF_getprop_alloc(package, name, elsz, buf); 462265967Sian if (retval == -1 || retval*elsz % 4 != 0) 463265967Sian return (-1); 464259255Sandreast 465259255Sandreast cell = *buf; 466259255Sandreast for (i = 0; i < retval*elsz/4; i++) 467259255Sandreast cell[i] = be32toh(cell[i]); 468259255Sandreast 469259255Sandreast return (retval); 470259255Sandreast} 471259255Sandreast 47267204Sobrien/* Get the next property of a package. */ 47367204Sobrienint 474186347SnwhitehornOF_nextprop(phandle_t package, const char *previous, char *buf, size_t size) 47567204Sobrien{ 476194138Smarius 477215049Snwhitehorn if (ofw_def_impl == NULL) 478215049Snwhitehorn return (-1); 479215049Snwhitehorn 480186347Snwhitehorn return (OFW_NEXTPROP(ofw_obj, package, previous, buf, size)); 48167204Sobrien} 48267204Sobrien 48367204Sobrien/* Set the value of a property of a package. */ 48467204Sobrienint 485186347SnwhitehornOF_setprop(phandle_t package, const char *propname, const void *buf, size_t len) 48667204Sobrien{ 487194138Smarius 488215049Snwhitehorn if (ofw_def_impl == NULL) 489215049Snwhitehorn return (-1); 490215049Snwhitehorn 491186347Snwhitehorn return (OFW_SETPROP(ofw_obj, package, propname, buf,len)); 49267204Sobrien} 49367204Sobrien 49467204Sobrien/* Convert a device specifier to a fully qualified pathname. */ 495186347Snwhitehornssize_t 496186347SnwhitehornOF_canon(const char *device, char *buf, size_t len) 49767204Sobrien{ 498194138Smarius 499215049Snwhitehorn if (ofw_def_impl == NULL) 500215049Snwhitehorn return (-1); 501215049Snwhitehorn 502186347Snwhitehorn return (OFW_CANON(ofw_obj, device, buf, len)); 50367204Sobrien} 50467204Sobrien 50567204Sobrien/* Return a package handle for the specified device. */ 50667204Sobrienphandle_t 50768548SbennoOF_finddevice(const char *device) 50867204Sobrien{ 509194138Smarius 510215049Snwhitehorn if (ofw_def_impl == NULL) 511215049Snwhitehorn return (-1); 512215049Snwhitehorn 513186347Snwhitehorn return (OFW_FINDDEVICE(ofw_obj, device)); 51467204Sobrien} 51567204Sobrien 51667204Sobrien/* Return the fully qualified pathname corresponding to an instance. */ 517186347Snwhitehornssize_t 518186347SnwhitehornOF_instance_to_path(ihandle_t instance, char *buf, size_t len) 51967204Sobrien{ 520194138Smarius 521215049Snwhitehorn if (ofw_def_impl == NULL) 522215049Snwhitehorn return (-1); 523215049Snwhitehorn 524186347Snwhitehorn return (OFW_INSTANCE_TO_PATH(ofw_obj, instance, buf, len)); 52567204Sobrien} 52667204Sobrien 52767204Sobrien/* Return the fully qualified pathname corresponding to a package. */ 528186347Snwhitehornssize_t 529186347SnwhitehornOF_package_to_path(phandle_t package, char *buf, size_t len) 53067204Sobrien{ 531194138Smarius 532215049Snwhitehorn if (ofw_def_impl == NULL) 533215049Snwhitehorn return (-1); 534215049Snwhitehorn 535186347Snwhitehorn return (OFW_PACKAGE_TO_PATH(ofw_obj, package, buf, len)); 53667204Sobrien} 53767204Sobrien 538255596Snwhitehorn/* Look up effective phandle (see FDT/PAPR spec) */ 539255596Snwhitehornstatic phandle_t 540255596SnwhitehornOF_child_xref_phandle(phandle_t parent, phandle_t xref) 541255596Snwhitehorn{ 542255596Snwhitehorn phandle_t child, rxref; 543255596Snwhitehorn 544255596Snwhitehorn /* 545255596Snwhitehorn * Recursively descend from parent, looking for a node with a property 546255596Snwhitehorn * named either "phandle", "ibm,phandle", or "linux,phandle" that 547255596Snwhitehorn * matches the xref we are looking for. 548255596Snwhitehorn */ 549255596Snwhitehorn 550255596Snwhitehorn for (child = OF_child(parent); child != 0; child = OF_peer(child)) { 551255596Snwhitehorn rxref = OF_child_xref_phandle(child, xref); 552255596Snwhitehorn if (rxref != -1) 553255596Snwhitehorn return (rxref); 554255596Snwhitehorn 555265967Sian if (OF_getencprop(child, "phandle", &rxref, sizeof(rxref)) == 556265967Sian -1 && OF_getencprop(child, "ibm,phandle", &rxref, 557265967Sian sizeof(rxref)) == -1 && OF_getencprop(child, 558255596Snwhitehorn "linux,phandle", &rxref, sizeof(rxref)) == -1) 559255596Snwhitehorn continue; 560255596Snwhitehorn 561255596Snwhitehorn if (rxref == xref) 562255596Snwhitehorn return (child); 563255596Snwhitehorn } 564255596Snwhitehorn 565255596Snwhitehorn return (-1); 566255596Snwhitehorn} 567255596Snwhitehorn 568255596Snwhitehornphandle_t 569273652SianOF_node_from_xref(phandle_t xref) 570255596Snwhitehorn{ 571273655Sian struct xrefinfo *xi; 572255596Snwhitehorn phandle_t node; 573255596Snwhitehorn 574273655Sian if (xref_init_done) { 575273655Sian if ((xi = xrefinfo_find(xref, FIND_BY_XREF)) == NULL) 576273655Sian return (xref); 577273655Sian return (xi->node); 578273655Sian } 579273655Sian 580273655Sian if ((node = OF_child_xref_phandle(OF_peer(0), xref)) == -1) 581255596Snwhitehorn return (xref); 582255596Snwhitehorn return (node); 583255596Snwhitehorn} 584255596Snwhitehorn 585273652Sianphandle_t 586273652SianOF_xref_from_node(phandle_t node) 587273652Sian{ 588273655Sian struct xrefinfo *xi; 589273652Sian phandle_t xref; 590273652Sian 591273655Sian if (xref_init_done) { 592273655Sian if ((xi = xrefinfo_find(node, FIND_BY_NODE)) == NULL) 593273655Sian return (node); 594273655Sian return (xi->xref); 595273655Sian } 596273655Sian 597273652Sian if (OF_getencprop(node, "phandle", &xref, sizeof(xref)) == 598273652Sian -1 && OF_getencprop(node, "ibm,phandle", &xref, 599273652Sian sizeof(xref)) == -1 && OF_getencprop(node, 600273652Sian "linux,phandle", &xref, sizeof(xref)) == -1) 601273652Sian return (node); 602273652Sian return (xref); 603273652Sian} 604273652Sian 605273655Siandevice_t 606273655SianOF_device_from_xref(phandle_t xref) 607273655Sian{ 608273655Sian struct xrefinfo *xi; 609273655Sian 610273655Sian if (xref_init_done) { 611273655Sian if ((xi = xrefinfo_find(xref, FIND_BY_XREF)) == NULL) 612273655Sian return (NULL); 613273655Sian return (xi->dev); 614273655Sian } 615273655Sian panic("Attempt to find device before xreflist_init"); 616273655Sian} 617273655Sian 618273655Sianphandle_t 619273655SianOF_xref_from_device(device_t dev) 620273655Sian{ 621273655Sian struct xrefinfo *xi; 622273655Sian 623273655Sian if (xref_init_done) { 624273655Sian if ((xi = xrefinfo_find((uintptr_t)dev, FIND_BY_DEV)) == NULL) 625273655Sian return (0); 626273655Sian return (xi->xref); 627273655Sian } 628273655Sian panic("Attempt to find xref before xreflist_init"); 629273655Sian} 630273655Sian 631273655Sianint 632273655SianOF_device_register_xref(phandle_t xref, device_t dev) 633273655Sian{ 634273655Sian struct xrefinfo *xi; 635273655Sian 636273655Sian /* 637273655Sian * If the given xref handle doesn't already exist in the list then we 638273655Sian * add a list entry. In theory this can only happen on a system where 639273655Sian * nodes don't contain phandle properties and xref and node handles are 640273655Sian * synonymous, so the xref handle is added as the node handle as well. 641273655Sian */ 642273655Sian if (xref_init_done) { 643273655Sian if ((xi = xrefinfo_find(xref, FIND_BY_XREF)) == NULL) 644273655Sian xrefinfo_add(xref, xref, dev); 645273655Sian else 646273655Sian xi->dev = dev; 647273655Sian return (0); 648273655Sian } 649273655Sian panic("Attempt to register device before xreflist_init"); 650273655Sian} 651273655Sian 65267204Sobrien/* Call the method in the scope of a given instance. */ 65367204Sobrienint 654186347SnwhitehornOF_call_method(const char *method, ihandle_t instance, int nargs, int nreturns, 655186347Snwhitehorn ...) 65667204Sobrien{ 65767204Sobrien va_list ap; 658209801Snwhitehorn cell_t args_n_results[12]; 659186347Snwhitehorn int n, status; 66067204Sobrien 661215049Snwhitehorn if (nargs > 6 || ofw_def_impl == NULL) 662170838Smarius return (-1); 66367204Sobrien va_start(ap, nreturns); 664186347Snwhitehorn for (n = 0; n < nargs; n++) 665209801Snwhitehorn args_n_results[n] = va_arg(ap, cell_t); 666186347Snwhitehorn 667186347Snwhitehorn status = OFW_CALL_METHOD(ofw_obj, instance, method, nargs, nreturns, 668186347Snwhitehorn args_n_results); 669186347Snwhitehorn if (status != 0) 670186347Snwhitehorn return (status); 671186347Snwhitehorn 672186347Snwhitehorn for (; n < nargs + nreturns; n++) 673209801Snwhitehorn *va_arg(ap, cell_t *) = args_n_results[n]; 67467204Sobrien va_end(ap); 675170838Smarius return (0); 67667204Sobrien} 67767204Sobrien 67867204Sobrien/* 679170838Smarius * Device I/O functions 68067204Sobrien */ 68167204Sobrien 68267204Sobrien/* Open an instance for a device. */ 68367204Sobrienihandle_t 684186347SnwhitehornOF_open(const char *device) 68567204Sobrien{ 686194138Smarius 687215049Snwhitehorn if (ofw_def_impl == NULL) 688215049Snwhitehorn return (0); 689215049Snwhitehorn 690186347Snwhitehorn return (OFW_OPEN(ofw_obj, device)); 69167204Sobrien} 69267204Sobrien 69367204Sobrien/* Close an instance. */ 69467204Sobrienvoid 69567204SobrienOF_close(ihandle_t instance) 69667204Sobrien{ 697194138Smarius 698215049Snwhitehorn if (ofw_def_impl == NULL) 699215049Snwhitehorn return; 700215049Snwhitehorn 701186347Snwhitehorn OFW_CLOSE(ofw_obj, instance); 70267204Sobrien} 70367204Sobrien 70467204Sobrien/* Read from an instance. */ 705186347Snwhitehornssize_t 706186347SnwhitehornOF_read(ihandle_t instance, void *addr, size_t len) 70767204Sobrien{ 708194138Smarius 709215049Snwhitehorn if (ofw_def_impl == NULL) 710215049Snwhitehorn return (-1); 711215049Snwhitehorn 712186347Snwhitehorn return (OFW_READ(ofw_obj, instance, addr, len)); 71367204Sobrien} 71467204Sobrien 71567204Sobrien/* Write to an instance. */ 716186347Snwhitehornssize_t 717186347SnwhitehornOF_write(ihandle_t instance, const void *addr, size_t len) 71867204Sobrien{ 719194138Smarius 720215049Snwhitehorn if (ofw_def_impl == NULL) 721215049Snwhitehorn return (-1); 722215049Snwhitehorn 723186347Snwhitehorn return (OFW_WRITE(ofw_obj, instance, addr, len)); 72467204Sobrien} 72567204Sobrien 72667204Sobrien/* Seek to a position. */ 72767204Sobrienint 728186347SnwhitehornOF_seek(ihandle_t instance, uint64_t pos) 72967204Sobrien{ 730194138Smarius 731215049Snwhitehorn if (ofw_def_impl == NULL) 732215049Snwhitehorn return (-1); 733215049Snwhitehorn 734186347Snwhitehorn return (OFW_SEEK(ofw_obj, instance, pos)); 73567204Sobrien} 73667204Sobrien 73767204Sobrien/* 738170838Smarius * Memory functions 73967204Sobrien */ 74067204Sobrien 74167204Sobrien/* Claim an area of memory. */ 74267204Sobrienvoid * 743186347SnwhitehornOF_claim(void *virt, size_t size, u_int align) 74467204Sobrien{ 745194138Smarius 746215049Snwhitehorn if (ofw_def_impl == NULL) 747215049Snwhitehorn return ((void *)-1); 748215049Snwhitehorn 749186347Snwhitehorn return (OFW_CLAIM(ofw_obj, virt, size, align)); 75067204Sobrien} 75167204Sobrien 75267204Sobrien/* Release an area of memory. */ 75367204Sobrienvoid 754186347SnwhitehornOF_release(void *virt, size_t size) 75567204Sobrien{ 756194138Smarius 757215049Snwhitehorn if (ofw_def_impl == NULL) 758215049Snwhitehorn return; 759215049Snwhitehorn 760186347Snwhitehorn OFW_RELEASE(ofw_obj, virt, size); 76167204Sobrien} 76267204Sobrien 76367204Sobrien/* 764170838Smarius * Control transfer functions 76567204Sobrien */ 76667204Sobrien 767133862Smarius/* Suspend and drop back to the Open Firmware interface. */ 76867204Sobrienvoid 76967204SobrienOF_enter() 77067204Sobrien{ 771194138Smarius 772215049Snwhitehorn if (ofw_def_impl == NULL) 773215049Snwhitehorn return; 774215049Snwhitehorn 775186347Snwhitehorn OFW_ENTER(ofw_obj); 77667204Sobrien} 77767204Sobrien 778133862Smarius/* Shut down and drop back to the Open Firmware interface. */ 77968548Sbennovoid 78067204SobrienOF_exit() 78167204Sobrien{ 782194138Smarius 783215049Snwhitehorn if (ofw_def_impl == NULL) 784215049Snwhitehorn panic("OF_exit: Open Firmware not available"); 785215049Snwhitehorn 786186347Snwhitehorn /* Should not return */ 787186347Snwhitehorn OFW_EXIT(ofw_obj); 78867204Sobrien 789170838Smarius for (;;) /* just in case */ 790170838Smarius ; 79167204Sobrien} 792