1296907Smmel/*- 2296907Smmel * Copyright 2016 Michal Meloun <mmel@FreeBSD.org> 3296907Smmel * All rights reserved. 4296907Smmel * 5296907Smmel * Redistribution and use in source and binary forms, with or without 6296907Smmel * modification, are permitted provided that the following conditions 7296907Smmel * are met: 8296907Smmel * 1. Redistributions of source code must retain the above copyright 9296907Smmel * notice, this list of conditions and the following disclaimer. 10296907Smmel * 2. Redistributions in binary form must reproduce the above copyright 11296907Smmel * notice, this list of conditions and the following disclaimer in the 12296907Smmel * documentation and/or other materials provided with the distribution. 13296907Smmel * 14296907Smmel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15296907Smmel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16296907Smmel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17296907Smmel * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18296907Smmel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19296907Smmel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20296907Smmel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21296907Smmel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22296907Smmel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23296907Smmel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24296907Smmel * SUCH DAMAGE. 25296907Smmel */ 26332025Smmel 27332025Smmel #include <sys/cdefs.h> 28332025Smmel__FBSDID("$FreeBSD: stable/11/sys/dev/extres/phy/phy.c 332025 2018-04-04 13:23:06Z mmel $"); 29332025Smmel 30296907Smmel#include "opt_platform.h" 31296907Smmel#include <sys/param.h> 32296907Smmel#include <sys/kernel.h> 33332025Smmel#include <sys/kobj.h> 34332025Smmel#include <sys/lock.h> 35296907Smmel#include <sys/malloc.h> 36332025Smmel#include <sys/queue.h> 37296907Smmel#include <sys/systm.h> 38332025Smmel#include <sys/sx.h> 39296907Smmel 40296907Smmel#ifdef FDT 41296907Smmel#include <dev/ofw/ofw_bus.h> 42296907Smmel#include <dev/ofw/ofw_bus_subr.h> 43296907Smmel#endif 44296907Smmel 45296907Smmel#include <dev/extres/phy/phy.h> 46296907Smmel 47332025Smmel#include "phydev_if.h" 48296907Smmel 49332025SmmelMALLOC_DEFINE(M_PHY, "phy", "Phy framework"); 50332025Smmel 51332025Smmel/* Forward declarations. */ 52332025Smmelstruct phy; 53332025Smmelstruct phynode; 54332025Smmel 55332025Smmeltypedef TAILQ_HEAD(phynode_list, phynode) phynode_list_t; 56332025Smmeltypedef TAILQ_HEAD(phy_list, phy) phy_list_t; 57332025Smmel 58332025Smmel/* Default phy methods. */ 59332025Smmelstatic int phynode_method_init(struct phynode *phynode); 60332025Smmelstatic int phynode_method_enable(struct phynode *phynode, bool disable); 61332025Smmelstatic int phynode_method_status(struct phynode *phynode, int *status); 62332025Smmel 63332025Smmel 64332025Smmel/* 65332025Smmel * Phy controller methods. 66332025Smmel */ 67332025Smmelstatic phynode_method_t phynode_methods[] = { 68332025Smmel PHYNODEMETHOD(phynode_init, phynode_method_init), 69332025Smmel PHYNODEMETHOD(phynode_enable, phynode_method_enable), 70332025Smmel PHYNODEMETHOD(phynode_status, phynode_method_status), 71332025Smmel 72332025Smmel PHYNODEMETHOD_END 73332025Smmel}; 74332025SmmelDEFINE_CLASS_0(phynode, phynode_class, phynode_methods, 0); 75332025Smmel 76332025Smmel/* 77332025Smmel * Phy node 78332025Smmel */ 79332025Smmelstruct phynode { 80332025Smmel KOBJ_FIELDS; 81332025Smmel 82332025Smmel TAILQ_ENTRY(phynode) phylist_link; /* Global list entry */ 83332025Smmel phy_list_t consumers_list; /* Consumers list */ 84332025Smmel 85332025Smmel 86332025Smmel /* Details of this device. */ 87332025Smmel const char *name; /* Globally unique name */ 88332025Smmel 89332025Smmel device_t pdev; /* Producer device_t */ 90332025Smmel void *softc; /* Producer softc */ 91332025Smmel intptr_t id; /* Per producer unique id */ 92332025Smmel#ifdef FDT 93332025Smmel phandle_t ofw_node; /* OFW node of phy */ 94332025Smmel#endif 95332025Smmel struct sx lock; /* Lock for this phy */ 96332025Smmel int ref_cnt; /* Reference counter */ 97332025Smmel int enable_cnt; /* Enabled counter */ 98332025Smmel}; 99332025Smmel 100296907Smmelstruct phy { 101332025Smmel device_t cdev; /* consumer device*/ 102332025Smmel struct phynode *phynode; 103332025Smmel TAILQ_ENTRY(phy) link; /* Consumers list entry */ 104332025Smmel 105332025Smmel int enable_cnt; 106296907Smmel}; 107296907Smmel 108332025Smmelstatic phynode_list_t phynode_list = TAILQ_HEAD_INITIALIZER(phynode_list); 109296907Smmel 110332025Smmelstatic struct sx phynode_topo_lock; 111332025SmmelSX_SYSINIT(phy_topology, &phynode_topo_lock, "Phy topology lock"); 112332025Smmel 113332025Smmel#define PHY_TOPO_SLOCK() sx_slock(&phynode_topo_lock) 114332025Smmel#define PHY_TOPO_XLOCK() sx_xlock(&phynode_topo_lock) 115332025Smmel#define PHY_TOPO_UNLOCK() sx_unlock(&phynode_topo_lock) 116332025Smmel#define PHY_TOPO_ASSERT() sx_assert(&phynode_topo_lock, SA_LOCKED) 117332025Smmel#define PHY_TOPO_XASSERT() sx_assert(&phynode_topo_lock, SA_XLOCKED) 118332025Smmel 119332025Smmel#define PHYNODE_SLOCK(_sc) sx_slock(&((_sc)->lock)) 120332025Smmel#define PHYNODE_XLOCK(_sc) sx_xlock(&((_sc)->lock)) 121332025Smmel#define PHYNODE_UNLOCK(_sc) sx_unlock(&((_sc)->lock)) 122332025Smmel 123332025Smmel/* ---------------------------------------------------------------------------- 124332025Smmel * 125332025Smmel * Default phy methods for base class. 126332025Smmel * 127332025Smmel */ 128332025Smmel 129332025Smmelstatic int 130332025Smmelphynode_method_init(struct phynode *phynode) 131332025Smmel{ 132332025Smmel 133332025Smmel return (0); 134332025Smmel} 135332025Smmel 136332025Smmelstatic int 137332025Smmelphynode_method_enable(struct phynode *phynode, bool enable) 138332025Smmel{ 139332025Smmel 140332025Smmel if (!enable) 141332025Smmel return (ENXIO); 142332025Smmel 143332025Smmel return (0); 144332025Smmel} 145332025Smmel 146332025Smmelstatic int 147332025Smmelphynode_method_status(struct phynode *phynode, int *status) 148332025Smmel{ 149332025Smmel *status = PHY_STATUS_ENABLED; 150332025Smmel return (0); 151332025Smmel} 152332025Smmel 153332025Smmel/* ---------------------------------------------------------------------------- 154332025Smmel * 155332025Smmel * Internal functions. 156332025Smmel * 157332025Smmel */ 158332025Smmel/* 159332025Smmel * Create and initialize phy object, but do not register it. 160332025Smmel */ 161332025Smmelstruct phynode * 162332025Smmelphynode_create(device_t pdev, phynode_class_t phynode_class, 163332025Smmel struct phynode_init_def *def) 164332025Smmel{ 165332025Smmel struct phynode *phynode; 166332025Smmel 167332025Smmel 168332025Smmel /* Create object and initialize it. */ 169332025Smmel phynode = malloc(sizeof(struct phynode), M_PHY, M_WAITOK | M_ZERO); 170332025Smmel kobj_init((kobj_t)phynode, (kobj_class_t)phynode_class); 171332025Smmel sx_init(&phynode->lock, "Phy node lock"); 172332025Smmel 173332025Smmel /* Allocate softc if required. */ 174332025Smmel if (phynode_class->size > 0) { 175332025Smmel phynode->softc = malloc(phynode_class->size, M_PHY, 176332025Smmel M_WAITOK | M_ZERO); 177332025Smmel } 178332025Smmel 179332025Smmel /* Rest of init. */ 180332025Smmel TAILQ_INIT(&phynode->consumers_list); 181332025Smmel phynode->id = def->id; 182332025Smmel phynode->pdev = pdev; 183332025Smmel#ifdef FDT 184332025Smmel phynode->ofw_node = def->ofw_node; 185332025Smmel#endif 186332025Smmel 187332025Smmel return (phynode); 188332025Smmel} 189332025Smmel 190332025Smmel/* Register phy object. */ 191332025Smmelstruct phynode * 192332025Smmelphynode_register(struct phynode *phynode) 193332025Smmel{ 194332025Smmel int rv; 195332025Smmel 196332025Smmel#ifdef FDT 197332025Smmel if (phynode->ofw_node <= 0) 198332025Smmel phynode->ofw_node = ofw_bus_get_node(phynode->pdev); 199332025Smmel if (phynode->ofw_node <= 0) 200332025Smmel return (NULL); 201332025Smmel#endif 202332025Smmel 203332025Smmel rv = PHYNODE_INIT(phynode); 204332025Smmel if (rv != 0) { 205332025Smmel printf("PHYNODE_INIT failed: %d\n", rv); 206332025Smmel return (NULL); 207332025Smmel } 208332025Smmel 209332025Smmel PHY_TOPO_XLOCK(); 210332025Smmel TAILQ_INSERT_TAIL(&phynode_list, phynode, phylist_link); 211332025Smmel PHY_TOPO_UNLOCK(); 212332025Smmel#ifdef FDT 213332025Smmel OF_device_register_xref(OF_xref_from_node(phynode->ofw_node), 214332025Smmel phynode->pdev); 215332025Smmel#endif 216332025Smmel return (phynode); 217332025Smmel} 218332025Smmel 219332025Smmelstatic struct phynode * 220332025Smmelphynode_find_by_id(device_t dev, intptr_t id) 221332025Smmel{ 222332025Smmel struct phynode *entry; 223332025Smmel 224332025Smmel PHY_TOPO_ASSERT(); 225332025Smmel 226332025Smmel TAILQ_FOREACH(entry, &phynode_list, phylist_link) { 227332025Smmel if ((entry->pdev == dev) && (entry->id == id)) 228332025Smmel return (entry); 229332025Smmel } 230332025Smmel 231332025Smmel return (NULL); 232332025Smmel} 233332025Smmel 234332025Smmel/* -------------------------------------------------------------------------- 235332025Smmel * 236332025Smmel * Phy providers interface 237332025Smmel * 238332025Smmel */ 239332025Smmel 240332025Smmelvoid * 241332025Smmelphynode_get_softc(struct phynode *phynode) 242332025Smmel{ 243332025Smmel 244332025Smmel return (phynode->softc); 245332025Smmel} 246332025Smmel 247332025Smmeldevice_t 248332025Smmelphynode_get_device(struct phynode *phynode) 249332025Smmel{ 250332025Smmel 251332025Smmel return (phynode->pdev); 252332025Smmel} 253332025Smmel 254332025Smmelintptr_t phynode_get_id(struct phynode *phynode) 255332025Smmel{ 256332025Smmel 257332025Smmel return (phynode->id); 258332025Smmel} 259332025Smmel 260332025Smmel#ifdef FDT 261332025Smmelphandle_t 262332025Smmelphynode_get_ofw_node(struct phynode *phynode) 263332025Smmel{ 264332025Smmel 265332025Smmel return (phynode->ofw_node); 266332025Smmel} 267332025Smmel#endif 268332025Smmel 269332025Smmel/* -------------------------------------------------------------------------- 270332025Smmel * 271332025Smmel * Real consumers executive 272332025Smmel * 273332025Smmel */ 274332025Smmel 275332025Smmel/* 276332025Smmel * Enable phy. 277332025Smmel */ 278296907Smmelint 279332025Smmelphynode_enable(struct phynode *phynode) 280296907Smmel{ 281332025Smmel int rv; 282296907Smmel 283332025Smmel PHY_TOPO_ASSERT(); 284332025Smmel 285332025Smmel PHYNODE_XLOCK(phynode); 286332025Smmel if (phynode->enable_cnt == 0) { 287332025Smmel rv = PHYNODE_ENABLE(phynode, true); 288332025Smmel if (rv != 0) { 289332025Smmel PHYNODE_UNLOCK(phynode); 290332025Smmel return (rv); 291332025Smmel } 292332025Smmel } 293332025Smmel phynode->enable_cnt++; 294332025Smmel PHYNODE_UNLOCK(phynode); 295332025Smmel return (0); 296296907Smmel} 297296907Smmel 298332025Smmel/* 299332025Smmel * Disable phy. 300332025Smmel */ 301296907Smmelint 302332025Smmelphynode_disable(struct phynode *phynode) 303296907Smmel{ 304332025Smmel int rv; 305296907Smmel 306332025Smmel PHY_TOPO_ASSERT(); 307332025Smmel 308332025Smmel PHYNODE_XLOCK(phynode); 309332025Smmel if (phynode->enable_cnt == 1) { 310332025Smmel rv = PHYNODE_ENABLE(phynode, false); 311332025Smmel if (rv != 0) { 312332025Smmel PHYNODE_UNLOCK(phynode); 313332025Smmel return (rv); 314332025Smmel } 315332025Smmel } 316332025Smmel phynode->enable_cnt--; 317332025Smmel PHYNODE_UNLOCK(phynode); 318332025Smmel return (0); 319296907Smmel} 320296907Smmel 321296907Smmel 322332025Smmel/* 323332025Smmel * Get phy status. (PHY_STATUS_*) 324332025Smmel */ 325296907Smmelint 326332025Smmelphynode_status(struct phynode *phynode, int *status) 327296907Smmel{ 328332025Smmel int rv; 329296907Smmel 330332025Smmel PHY_TOPO_ASSERT(); 331332025Smmel 332332025Smmel PHYNODE_XLOCK(phynode); 333332025Smmel rv = PHYNODE_STATUS(phynode, status); 334332025Smmel PHYNODE_UNLOCK(phynode); 335332025Smmel return (rv); 336296907Smmel} 337296907Smmel 338332025Smmel /* -------------------------------------------------------------------------- 339332025Smmel * 340332025Smmel * Phy consumers interface. 341332025Smmel * 342332025Smmel */ 343332025Smmel 344332025Smmel/* Helper function for phy_get*() */ 345332025Smmelstatic phy_t 346332025Smmelphy_create(struct phynode *phynode, device_t cdev) 347332025Smmel{ 348332025Smmel struct phy *phy; 349332025Smmel 350332025Smmel PHY_TOPO_ASSERT(); 351332025Smmel 352332025Smmel phy = malloc(sizeof(struct phy), M_PHY, M_WAITOK | M_ZERO); 353332025Smmel phy->cdev = cdev; 354332025Smmel phy->phynode = phynode; 355332025Smmel phy->enable_cnt = 0; 356332025Smmel 357332025Smmel PHYNODE_XLOCK(phynode); 358332025Smmel phynode->ref_cnt++; 359332025Smmel TAILQ_INSERT_TAIL(&phynode->consumers_list, phy, link); 360332025Smmel PHYNODE_UNLOCK(phynode); 361332025Smmel 362332025Smmel return (phy); 363332025Smmel} 364332025Smmel 365296907Smmelint 366332025Smmelphy_enable(phy_t phy) 367296907Smmel{ 368332025Smmel int rv; 369332025Smmel struct phynode *phynode; 370296907Smmel 371332025Smmel phynode = phy->phynode; 372332025Smmel KASSERT(phynode->ref_cnt > 0, 373332025Smmel ("Attempt to access unreferenced phy.\n")); 374332025Smmel 375332025Smmel PHY_TOPO_SLOCK(); 376332025Smmel rv = phynode_enable(phynode); 377332025Smmel if (rv == 0) 378332025Smmel phy->enable_cnt++; 379332025Smmel PHY_TOPO_UNLOCK(); 380332025Smmel return (rv); 381296907Smmel} 382296907Smmel 383296907Smmelint 384332025Smmelphy_disable(phy_t phy) 385296907Smmel{ 386332025Smmel int rv; 387332025Smmel struct phynode *phynode; 388296907Smmel 389332025Smmel phynode = phy->phynode; 390332025Smmel KASSERT(phynode->ref_cnt > 0, 391332025Smmel ("Attempt to access unreferenced phy.\n")); 392332025Smmel KASSERT(phy->enable_cnt > 0, 393332025Smmel ("Attempt to disable already disabled phy.\n")); 394332025Smmel 395332025Smmel PHY_TOPO_SLOCK(); 396332025Smmel rv = phynode_disable(phynode); 397332025Smmel if (rv == 0) 398332025Smmel phy->enable_cnt--; 399332025Smmel PHY_TOPO_UNLOCK(); 400332025Smmel return (rv); 401296907Smmel} 402296907Smmel 403296907Smmelint 404332025Smmelphy_status(phy_t phy, int *status) 405332025Smmel{ 406332025Smmel int rv; 407332025Smmel struct phynode *phynode; 408332025Smmel 409332025Smmel phynode = phy->phynode; 410332025Smmel KASSERT(phynode->ref_cnt > 0, 411332025Smmel ("Attempt to access unreferenced phy.\n")); 412332025Smmel 413332025Smmel PHY_TOPO_SLOCK(); 414332025Smmel rv = phynode_status(phynode, status); 415332025Smmel PHY_TOPO_UNLOCK(); 416332025Smmel return (rv); 417332025Smmel} 418332025Smmel 419332025Smmelint 420296907Smmelphy_get_by_id(device_t consumer_dev, device_t provider_dev, intptr_t id, 421332025Smmel phy_t *phy) 422296907Smmel{ 423332025Smmel struct phynode *phynode; 424296907Smmel 425332025Smmel PHY_TOPO_SLOCK(); 426332025Smmel 427332025Smmel phynode = phynode_find_by_id(provider_dev, id); 428332025Smmel if (phynode == NULL) { 429332025Smmel PHY_TOPO_UNLOCK(); 430332025Smmel return (ENODEV); 431332025Smmel } 432332025Smmel *phy = phy_create(phynode, consumer_dev); 433332025Smmel PHY_TOPO_UNLOCK(); 434332025Smmel 435296907Smmel return (0); 436296907Smmel} 437296907Smmel 438296907Smmelvoid 439296907Smmelphy_release(phy_t phy) 440296907Smmel{ 441332025Smmel struct phynode *phynode; 442332025Smmel 443332025Smmel phynode = phy->phynode; 444332025Smmel KASSERT(phynode->ref_cnt > 0, 445332025Smmel ("Attempt to access unreferenced phy.\n")); 446332025Smmel 447332025Smmel PHY_TOPO_SLOCK(); 448332025Smmel while (phy->enable_cnt > 0) { 449332025Smmel phynode_disable(phynode); 450332025Smmel phy->enable_cnt--; 451332025Smmel } 452332025Smmel PHYNODE_XLOCK(phynode); 453332025Smmel TAILQ_REMOVE(&phynode->consumers_list, phy, link); 454332025Smmel phynode->ref_cnt--; 455332025Smmel PHYNODE_UNLOCK(phynode); 456332025Smmel PHY_TOPO_UNLOCK(); 457332025Smmel 458296907Smmel free(phy, M_PHY); 459296907Smmel} 460296907Smmel 461296907Smmel#ifdef FDT 462332025Smmelint phydev_default_ofw_map(device_t provider, phandle_t xref, int ncells, 463296907Smmel pcell_t *cells, intptr_t *id) 464296907Smmel{ 465332025Smmel struct phynode *entry; 466332025Smmel phandle_t node; 467296907Smmel 468332025Smmel /* Single device can register multiple subnodes. */ 469332025Smmel if (ncells == 0) { 470332025Smmel 471332025Smmel node = OF_node_from_xref(xref); 472332025Smmel PHY_TOPO_XLOCK(); 473332025Smmel TAILQ_FOREACH(entry, &phynode_list, phylist_link) { 474332025Smmel if ((entry->pdev == provider) && 475332025Smmel (entry->ofw_node == node)) { 476332025Smmel *id = entry->id; 477332025Smmel PHY_TOPO_UNLOCK(); 478332025Smmel return (0); 479332025Smmel } 480332025Smmel } 481332025Smmel PHY_TOPO_UNLOCK(); 482332025Smmel return (ERANGE); 483332025Smmel } 484332025Smmel 485332025Smmel /* First cell is ID. */ 486332025Smmel if (ncells == 1) { 487296907Smmel *id = cells[0]; 488332025Smmel return (0); 489332025Smmel } 490296907Smmel 491332025Smmel /* No default way how to get ID, custom mapper is required. */ 492332025Smmel return (ERANGE); 493296907Smmel} 494296907Smmel 495296907Smmelint 496308324Smmelphy_get_by_ofw_idx(device_t consumer_dev, phandle_t cnode, int idx, phy_t *phy) 497296907Smmel{ 498308324Smmel phandle_t xnode; 499296907Smmel pcell_t *cells; 500296907Smmel device_t phydev; 501296907Smmel int ncells, rv; 502296907Smmel intptr_t id; 503296907Smmel 504308324Smmel if (cnode <= 0) 505308324Smmel cnode = ofw_bus_get_node(consumer_dev); 506296907Smmel if (cnode <= 0) { 507296907Smmel device_printf(consumer_dev, 508296907Smmel "%s called on not ofw based device\n", __func__); 509296907Smmel return (ENXIO); 510296907Smmel } 511296907Smmel rv = ofw_bus_parse_xref_list_alloc(cnode, "phys", "#phy-cells", idx, 512296907Smmel &xnode, &ncells, &cells); 513296907Smmel if (rv != 0) 514296907Smmel return (rv); 515296907Smmel 516296907Smmel /* Tranlate provider to device. */ 517296907Smmel phydev = OF_device_from_xref(xnode); 518296907Smmel if (phydev == NULL) { 519299714Sgonzo OF_prop_free(cells); 520296907Smmel return (ENODEV); 521296907Smmel } 522296907Smmel /* Map phy to number. */ 523332025Smmel rv = PHYDEV_MAP(phydev, xnode, ncells, cells, &id); 524299714Sgonzo OF_prop_free(cells); 525296907Smmel if (rv != 0) 526296907Smmel return (rv); 527296907Smmel 528296907Smmel return (phy_get_by_id(consumer_dev, phydev, id, phy)); 529296907Smmel} 530296907Smmel 531296907Smmelint 532308324Smmelphy_get_by_ofw_name(device_t consumer_dev, phandle_t cnode, char *name, 533308324Smmel phy_t *phy) 534296907Smmel{ 535296907Smmel int rv, idx; 536296907Smmel 537308324Smmel if (cnode <= 0) 538308324Smmel cnode = ofw_bus_get_node(consumer_dev); 539296907Smmel if (cnode <= 0) { 540296907Smmel device_printf(consumer_dev, 541296907Smmel "%s called on not ofw based device\n", __func__); 542296907Smmel return (ENXIO); 543296907Smmel } 544296907Smmel rv = ofw_bus_find_string_index(cnode, "phy-names", name, &idx); 545296907Smmel if (rv != 0) 546296907Smmel return (rv); 547308324Smmel return (phy_get_by_ofw_idx(consumer_dev, cnode, idx, phy)); 548296907Smmel} 549296907Smmel 550296907Smmelint 551308324Smmelphy_get_by_ofw_property(device_t consumer_dev, phandle_t cnode, char *name, 552308324Smmel phy_t *phy) 553296907Smmel{ 554296907Smmel pcell_t *cells; 555296907Smmel device_t phydev; 556296907Smmel int ncells, rv; 557296907Smmel intptr_t id; 558296907Smmel 559308324Smmel if (cnode <= 0) 560308324Smmel cnode = ofw_bus_get_node(consumer_dev); 561296907Smmel if (cnode <= 0) { 562296907Smmel device_printf(consumer_dev, 563296907Smmel "%s called on not ofw based device\n", __func__); 564296907Smmel return (ENXIO); 565296907Smmel } 566296907Smmel ncells = OF_getencprop_alloc(cnode, name, sizeof(pcell_t), 567296907Smmel (void **)&cells); 568296907Smmel if (ncells < 1) 569296907Smmel return (ENXIO); 570296907Smmel 571296907Smmel /* Tranlate provider to device. */ 572296907Smmel phydev = OF_device_from_xref(cells[0]); 573296907Smmel if (phydev == NULL) { 574299714Sgonzo OF_prop_free(cells); 575296907Smmel return (ENODEV); 576296907Smmel } 577296907Smmel /* Map phy to number. */ 578332025Smmel rv = PHYDEV_MAP(phydev, cells[0], ncells - 1 , cells + 1, &id); 579299714Sgonzo OF_prop_free(cells); 580296907Smmel if (rv != 0) 581296907Smmel return (rv); 582296907Smmel 583296907Smmel return (phy_get_by_id(consumer_dev, phydev, id, phy)); 584296907Smmel} 585296907Smmel#endif 586