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