17aec1d6eScindi /*
27aec1d6eScindi * CDDL HEADER START
37aec1d6eScindi *
47aec1d6eScindi * The contents of this file are subject to the terms of the
57aec1d6eScindi * Common Development and Distribution License (the "License").
67aec1d6eScindi * You may not use this file except in compliance with the License.
77aec1d6eScindi *
87aec1d6eScindi * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97aec1d6eScindi * or http://www.opensolaris.org/os/licensing.
107aec1d6eScindi * See the License for the specific language governing permissions
117aec1d6eScindi * and limitations under the License.
127aec1d6eScindi *
137aec1d6eScindi * When distributing Covered Code, include this CDDL HEADER in each
147aec1d6eScindi * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157aec1d6eScindi * If applicable, add the following below this CDDL HEADER, with the
167aec1d6eScindi * fields enclosed by brackets "[]" replaced with your own identifying
177aec1d6eScindi * information: Portions Copyright [yyyy] [name of copyright owner]
187aec1d6eScindi *
197aec1d6eScindi * CDDL HEADER END
207aec1d6eScindi */
217aec1d6eScindi
227aec1d6eScindi /*
23d4bc0535SKrishna Elango * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
247aec1d6eScindi * Use is subject to license terms.
257aec1d6eScindi */
267aec1d6eScindi
277aec1d6eScindi #include <fm/topo_mod.h>
280eb822a1Scindi #include <fm/topo_hc.h>
297aec1d6eScindi #include <libdevinfo.h>
3000d0963fSdilpreet #include <strings.h>
310eb822a1Scindi #include <pcibus.h>
320eb822a1Scindi #include <hostbridge.h>
330eb822a1Scindi #include <did.h>
340eb822a1Scindi #include <util.h>
357aec1d6eScindi
367aec1d6eScindi static int
hb_process(topo_mod_t * mod,tnode_t * ptn,topo_instance_t hbi,di_node_t bn)370eb822a1Scindi hb_process(topo_mod_t *mod, tnode_t *ptn, topo_instance_t hbi, di_node_t bn)
387aec1d6eScindi {
397aec1d6eScindi tnode_t *hb;
400eb822a1Scindi did_t *hbdid;
417aec1d6eScindi
420eb822a1Scindi if ((hbdid = did_create(mod, bn, 0, hbi, NO_RC, TRUST_BDF)) == NULL)
437aec1d6eScindi return (-1);
440eb822a1Scindi if ((hb = pcihostbridge_declare(mod, ptn, bn, hbi)) == NULL)
457aec1d6eScindi return (-1);
4612cc75c8Scindi if (topo_mod_enumerate(mod,
4712cc75c8Scindi hb, PCI_BUS, PCI_BUS, 0, MAX_HB_BUSES, (void *)hbdid) < 0) {
4812cc75c8Scindi topo_node_unbind(hb);
4912cc75c8Scindi return (-1);
5012cc75c8Scindi }
5112cc75c8Scindi
5212cc75c8Scindi return (0);
537aec1d6eScindi }
547aec1d6eScindi
557aec1d6eScindi static int
rc_process(topo_mod_t * mod,tnode_t * ptn,topo_instance_t hbi,di_node_t bn)560eb822a1Scindi rc_process(topo_mod_t *mod, tnode_t *ptn, topo_instance_t hbi, di_node_t bn)
577aec1d6eScindi {
587aec1d6eScindi tnode_t *hb;
597aec1d6eScindi tnode_t *rc;
600eb822a1Scindi did_t *hbdid;
617aec1d6eScindi
620eb822a1Scindi if ((hbdid = did_create(mod, bn, 0, hbi, hbi, TRUST_BDF)) == NULL)
637aec1d6eScindi return (-1);
640eb822a1Scindi if ((hb = pciexhostbridge_declare(mod, ptn, bn, hbi)) == NULL)
657aec1d6eScindi return (-1);
660eb822a1Scindi if ((rc = pciexrc_declare(mod, hb, bn, hbi)) == NULL)
677aec1d6eScindi return (-1);
6812cc75c8Scindi if (topo_mod_enumerate(mod,
6912cc75c8Scindi rc, PCI_BUS, PCIEX_BUS, 0, MAX_HB_BUSES, (void *)hbdid) < 0) {
7012cc75c8Scindi topo_node_unbind(hb);
7112cc75c8Scindi topo_node_unbind(rc);
7212cc75c8Scindi return (-1);
7312cc75c8Scindi }
7412cc75c8Scindi
7512cc75c8Scindi return (0);
767aec1d6eScindi }
777aec1d6eScindi
787aec1d6eScindi
797aec1d6eScindi int
pci_hostbridges_find(topo_mod_t * mod,tnode_t * ptn)800eb822a1Scindi pci_hostbridges_find(topo_mod_t *mod, tnode_t *ptn)
817aec1d6eScindi {
827aec1d6eScindi di_node_t devtree;
830eb822a1Scindi di_node_t pnode, cnode;
847aec1d6eScindi int hbcnt = 0;
857aec1d6eScindi
867aec1d6eScindi /* Scan for buses, top-level devinfo nodes with the right driver */
870eb822a1Scindi devtree = topo_mod_devinfo(mod);
887aec1d6eScindi if (devtree == DI_NODE_NIL) {
89724365f7Ssethg topo_mod_dprintf(mod, "devinfo init failed.");
907aec1d6eScindi topo_node_range_destroy(ptn, HOSTBRIDGE);
917aec1d6eScindi return (0);
927aec1d6eScindi }
937aec1d6eScindi
947aec1d6eScindi pnode = di_drv_first_node(PCI, devtree);
957aec1d6eScindi while (pnode != DI_NODE_NIL) {
96*6de7dd38SRobert Mustacchi /*
97*6de7dd38SRobert Mustacchi * We've seen cases where certain phantom PCI hostbridges have
98*6de7dd38SRobert Mustacchi * appeared on systems. If we encounter a host bridge without a
99*6de7dd38SRobert Mustacchi * bus address assigned to it, then we should skip processing it
100*6de7dd38SRobert Mustacchi * here as that indicates that it generally doesn't have any
101*6de7dd38SRobert Mustacchi * devices under it and we'll otherwise blow up in devinfo.
102*6de7dd38SRobert Mustacchi */
103*6de7dd38SRobert Mustacchi if (di_bus_addr(pnode) == NULL) {
104*6de7dd38SRobert Mustacchi pnode = di_drv_next_node(pnode);
105*6de7dd38SRobert Mustacchi continue;
106*6de7dd38SRobert Mustacchi }
107*6de7dd38SRobert Mustacchi
10812cc75c8Scindi if (hb_process(mod, ptn, hbcnt, pnode) < 0) {
10912cc75c8Scindi if (hbcnt == 0)
1107aec1d6eScindi topo_node_range_destroy(ptn, HOSTBRIDGE);
111724365f7Ssethg return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
1127aec1d6eScindi }
11312cc75c8Scindi hbcnt++;
1147aec1d6eScindi pnode = di_drv_next_node(pnode);
1157aec1d6eScindi }
1167aec1d6eScindi
1177aec1d6eScindi pnode = di_drv_first_node(NPE, devtree);
1187aec1d6eScindi while (pnode != DI_NODE_NIL) {
11900d0963fSdilpreet for (cnode = di_child_node(pnode); cnode != DI_NODE_NIL;
12000d0963fSdilpreet cnode = di_sibling_node(cnode)) {
12100d0963fSdilpreet if (di_driver_name(cnode) == NULL)
12200d0963fSdilpreet continue;
12300d0963fSdilpreet if (strcmp(di_driver_name(cnode), PCI_PCI) == 0) {
12412cc75c8Scindi if (hb_process(mod, ptn, hbcnt, cnode) < 0) {
12512cc75c8Scindi if (hbcnt == 0)
12600d0963fSdilpreet topo_node_range_destroy(ptn,
12700d0963fSdilpreet HOSTBRIDGE);
128724365f7Ssethg return (topo_mod_seterrno(mod,
12900d0963fSdilpreet EMOD_PARTIAL_ENUM));
13000d0963fSdilpreet }
13112cc75c8Scindi hbcnt++;
13200d0963fSdilpreet }
133d4bc0535SKrishna Elango if (strcmp(di_driver_name(cnode), PCIEB) == 0) {
13412cc75c8Scindi if (rc_process(mod, ptn, hbcnt, cnode) < 0) {
13512cc75c8Scindi if (hbcnt == 0)
13600d0963fSdilpreet topo_node_range_destroy(ptn,
13700d0963fSdilpreet HOSTBRIDGE);
138724365f7Ssethg return (topo_mod_seterrno(mod,
13900d0963fSdilpreet EMOD_PARTIAL_ENUM));
14000d0963fSdilpreet }
14112cc75c8Scindi hbcnt++;
14200d0963fSdilpreet }
1437aec1d6eScindi }
1447aec1d6eScindi pnode = di_drv_next_node(pnode);
1457aec1d6eScindi }
1467aec1d6eScindi return (0);
1477aec1d6eScindi }
1487aec1d6eScindi
1497aec1d6eScindi /*ARGSUSED*/
1507aec1d6eScindi int
platform_hb_enum(topo_mod_t * mod,tnode_t * parent,const char * name,topo_instance_t imin,topo_instance_t imax)1510eb822a1Scindi platform_hb_enum(topo_mod_t *mod, tnode_t *parent, const char *name,
1520eb822a1Scindi topo_instance_t imin, topo_instance_t imax)
1537aec1d6eScindi {
1540eb822a1Scindi return (pci_hostbridges_find(mod, parent));
1557aec1d6eScindi }
1567aec1d6eScindi
1577aec1d6eScindi /*ARGSUSED*/
1587aec1d6eScindi int
platform_hb_label(topo_mod_t * mod,tnode_t * node,nvlist_t * in,nvlist_t ** out)1590eb822a1Scindi platform_hb_label(topo_mod_t *mod, tnode_t *node, nvlist_t *in, nvlist_t **out)
1607aec1d6eScindi {
161724365f7Ssethg return (labelmethod_inherit(mod, node, in, out));
1627aec1d6eScindi }
163