15430Ssd77468 /*
25430Ssd77468 * CDDL HEADER START
35430Ssd77468 *
45430Ssd77468 * The contents of this file are subject to the terms of the
55430Ssd77468 * Common Development and Distribution License (the "License").
65430Ssd77468 * You may not use this file except in compliance with the License.
75430Ssd77468 *
85430Ssd77468 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95430Ssd77468 * or http://www.opensolaris.org/os/licensing.
105430Ssd77468 * See the License for the specific language governing permissions
115430Ssd77468 * and limitations under the License.
125430Ssd77468 *
135430Ssd77468 * When distributing Covered Code, include this CDDL HEADER in each
145430Ssd77468 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155430Ssd77468 * If applicable, add the following below this CDDL HEADER, with the
165430Ssd77468 * fields enclosed by brackets "[]" replaced with your own identifying
175430Ssd77468 * information: Portions Copyright [yyyy] [name of copyright owner]
185430Ssd77468 *
195430Ssd77468 * CDDL HEADER END
205430Ssd77468 */
215430Ssd77468
225430Ssd77468 /*
23*11583SSurya.Prakki@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
245430Ssd77468 * Use is subject to license terms.
255430Ssd77468 */
265430Ssd77468
275430Ssd77468 #include <string.h>
285430Ssd77468 #include <strings.h>
295430Ssd77468 #include <libdevinfo.h>
305430Ssd77468 #include <fm/topo_mod.h>
315430Ssd77468 #include <fm/topo_hc.h>
325430Ssd77468 #include <sys/fm/protocol.h>
335430Ssd77468 #include "cpuboard_topo.h"
345430Ssd77468
355430Ssd77468 static const topo_pgroup_info_t io_pgroup =
365430Ssd77468 { TOPO_PGROUP_IO, TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
375430Ssd77468 static const topo_pgroup_info_t pci_pgroup =
385430Ssd77468 { TOPO_PGROUP_PCI, TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
395430Ssd77468
405430Ssd77468 static tnode_t *
cpuboard_node_create(topo_mod_t * mp,tnode_t * parent,const char * name,int inst,void * priv)415430Ssd77468 cpuboard_node_create(topo_mod_t *mp, tnode_t *parent, const char *name,
425430Ssd77468 int inst, void *priv)
435430Ssd77468 {
445430Ssd77468 tnode_t *node;
455430Ssd77468 nvlist_t *fmri;
465430Ssd77468 nvlist_t *auth = topo_mod_auth(mp, parent);
475430Ssd77468
485430Ssd77468 topo_mod_dprintf(mp, "cpuboard_node_create:\n");
495430Ssd77468
505430Ssd77468 if (parent == NULL || inst < 0) {
515430Ssd77468 return (NULL);
525430Ssd77468 }
535430Ssd77468
545430Ssd77468 /* Create FMRI */
555430Ssd77468 if ((fmri = topo_mod_hcfmri(mp, parent, FM_HC_SCHEME_VERSION, name,
565430Ssd77468 inst, NULL, auth, NULL, NULL, NULL)) == NULL) {
575430Ssd77468 topo_mod_dprintf(mp, "create of tnode for %s failed: %s",
585430Ssd77468 name, topo_strerror(topo_mod_errno(mp)));
595430Ssd77468 nvlist_free(auth);
605430Ssd77468 return (NULL);
615430Ssd77468 }
625430Ssd77468 nvlist_free(auth);
635430Ssd77468
645430Ssd77468 /* Create and bind node */
655430Ssd77468 node = topo_node_bind(mp, parent, name, inst, fmri);
665430Ssd77468 if (node == NULL) {
675430Ssd77468 nvlist_free(fmri);
685430Ssd77468 topo_mod_dprintf(mp, "unable to bind root complex: %s\n",
695430Ssd77468 topo_strerror(topo_mod_errno(mp)));
705430Ssd77468 return (NULL); /* mod_errno already set */
715430Ssd77468 }
725430Ssd77468
735430Ssd77468 nvlist_free(fmri);
745430Ssd77468 topo_node_setspecific(node, priv);
755430Ssd77468
765430Ssd77468 return (node);
775430Ssd77468 }
785430Ssd77468
795430Ssd77468 /*
807850SVuong.Nguyen@Sun.COM * cpuboard_rc_node_create()
817850SVuong.Nguyen@Sun.COM * Description:
827850SVuong.Nguyen@Sun.COM * Create a root complex node pciexrc
837850SVuong.Nguyen@Sun.COM * Parameters:
847850SVuong.Nguyen@Sun.COM * mp: topo module pointer
857850SVuong.Nguyen@Sun.COM * parent: topo parent node of the newly created pciexrc node
867850SVuong.Nguyen@Sun.COM * dnode: Solaris device node of the root complex
877850SVuong.Nguyen@Sun.COM * rcpath: Used to populated the dev property of the topo pciexrc node if
887850SVuong.Nguyen@Sun.COM * the local host does not own the root complex.
895430Ssd77468 */
905430Ssd77468 static tnode_t *
cpuboard_rc_node_create(topo_mod_t * mp,tnode_t * parent,di_node_t dnode,char * rcpath,int inst)915430Ssd77468 cpuboard_rc_node_create(topo_mod_t *mp, tnode_t *parent, di_node_t dnode,
927850SVuong.Nguyen@Sun.COM char *rcpath, int inst)
935430Ssd77468 {
945430Ssd77468 int err;
955430Ssd77468 tnode_t *rcn;
965430Ssd77468 char *dnpath;
975430Ssd77468 nvlist_t *mod;
985430Ssd77468
995430Ssd77468 topo_mod_dprintf(mp, "cpuboard_rc_node_create:\n");
1005430Ssd77468
1015430Ssd77468 rcn = cpuboard_node_create(mp, parent, PCIEX_ROOT, inst, (void *)dnode);
1025430Ssd77468 if (rcn == NULL) {
1035430Ssd77468 return (NULL);
1045430Ssd77468 }
1055430Ssd77468
1065430Ssd77468 /* Inherit parent FRU's label */
1075430Ssd77468 (void) topo_node_fru_set(rcn, NULL, 0, &err);
1085430Ssd77468 (void) topo_node_label_set(rcn, NULL, &err);
1095430Ssd77468
1105430Ssd77468 /*
1115430Ssd77468 * Set ASRU to be the dev-scheme ASRU
1125430Ssd77468 */
1135430Ssd77468 if ((dnpath = di_devfs_path(dnode)) != NULL) {
1145430Ssd77468 nvlist_t *fmri;
1155430Ssd77468
1167850SVuong.Nguyen@Sun.COM /*
1177850SVuong.Nguyen@Sun.COM * The local host owns the root complex, so use the dev path
1187850SVuong.Nguyen@Sun.COM * from the di_devfs_path(), instead of the passed in rcpath,
1197850SVuong.Nguyen@Sun.COM * to populate the dev property.
1207850SVuong.Nguyen@Sun.COM */
1217850SVuong.Nguyen@Sun.COM rcpath = dnpath;
1225430Ssd77468 fmri = topo_mod_devfmri(mp, FM_DEV_SCHEME_VERSION,
1235430Ssd77468 dnpath, NULL);
1245430Ssd77468 if (fmri == NULL) {
1255430Ssd77468 topo_mod_dprintf(mp,
1265430Ssd77468 "dev:///%s fmri creation failed.\n",
1275430Ssd77468 dnpath);
128*11583SSurya.Prakki@Sun.COM (void) topo_mod_seterrno(mp, err);
1295430Ssd77468 di_devfs_path_free(dnpath);
1305430Ssd77468 return (NULL);
1315430Ssd77468 }
1325430Ssd77468 if (topo_node_asru_set(rcn, fmri, 0, &err) < 0) {
1335430Ssd77468 topo_mod_dprintf(mp, "topo_node_asru_set failed\n");
134*11583SSurya.Prakki@Sun.COM (void) topo_mod_seterrno(mp, err);
1355430Ssd77468 nvlist_free(fmri);
1365430Ssd77468 di_devfs_path_free(dnpath);
1375430Ssd77468 return (NULL);
1385430Ssd77468 }
1395430Ssd77468 nvlist_free(fmri);
1405430Ssd77468 } else {
1415430Ssd77468 topo_mod_dprintf(mp, "NULL di_devfs_path.\n");
1425430Ssd77468 }
1435430Ssd77468
1445430Ssd77468 /*
1455430Ssd77468 * Set pciexrc properties for root complex nodes
1465430Ssd77468 */
1475430Ssd77468
1485430Ssd77468 /* Add the io and pci property groups */
1495430Ssd77468 if (topo_pgroup_create(rcn, &io_pgroup, &err) < 0) {
1505430Ssd77468 topo_mod_dprintf(mp, "topo_pgroup_create failed\n");
1515430Ssd77468 di_devfs_path_free(dnpath);
152*11583SSurya.Prakki@Sun.COM (void) topo_mod_seterrno(mp, err);
1535430Ssd77468 return (NULL);
1545430Ssd77468 }
1555430Ssd77468 if (topo_pgroup_create(rcn, &pci_pgroup, &err) < 0) {
1565430Ssd77468 topo_mod_dprintf(mp, "topo_pgroup_create failed\n");
1575430Ssd77468 di_devfs_path_free(dnpath);
158*11583SSurya.Prakki@Sun.COM (void) topo_mod_seterrno(mp, err);
1595430Ssd77468 return (NULL);
1605430Ssd77468 }
1615430Ssd77468 /* Add the devfs path property */
1627850SVuong.Nguyen@Sun.COM if (rcpath) {
1635430Ssd77468 if (topo_prop_set_string(rcn, TOPO_PGROUP_IO, TOPO_IO_DEV,
1647850SVuong.Nguyen@Sun.COM TOPO_PROP_IMMUTABLE, rcpath, &err) != 0) {
1655430Ssd77468 topo_mod_dprintf(mp, "Failed to set DEV property\n");
166*11583SSurya.Prakki@Sun.COM (void) topo_mod_seterrno(mp, err);
1675430Ssd77468 }
1687850SVuong.Nguyen@Sun.COM }
1697850SVuong.Nguyen@Sun.COM if (dnpath) {
1705430Ssd77468 di_devfs_path_free(dnpath);
1715430Ssd77468 }
1725430Ssd77468 /* T5440 device type is always "pciex" */
1735430Ssd77468 if (topo_prop_set_string(rcn, TOPO_PGROUP_IO, TOPO_IO_DEVTYPE,
1745430Ssd77468 TOPO_PROP_IMMUTABLE, CPUBOARD_PX_DEVTYPE, &err) != 0) {
1755430Ssd77468 topo_mod_dprintf(mp, "Failed to set DEVTYPE property\n");
1765430Ssd77468 }
1775430Ssd77468 /* T5440 driver is always "px" */
1785430Ssd77468 if (topo_prop_set_string(rcn, TOPO_PGROUP_IO, TOPO_IO_DRIVER,
1795430Ssd77468 TOPO_PROP_IMMUTABLE, CPUBOARD_PX_DRV, &err) != 0) {
1805430Ssd77468 topo_mod_dprintf(mp, "Failed to set DRIVER property\n");
1815430Ssd77468 }
1825430Ssd77468 if ((mod = topo_mod_modfmri(mp, FM_MOD_SCHEME_VERSION, CPUBOARD_PX_DRV))
1835430Ssd77468 == NULL || topo_prop_set_fmri(rcn, TOPO_PGROUP_IO,
1845430Ssd77468 TOPO_IO_MODULE, TOPO_PROP_IMMUTABLE, mod, &err) != 0) {
1855430Ssd77468 topo_mod_dprintf(mp, "Failed to set MODULE property\n");
1865430Ssd77468 }
1875430Ssd77468 if (mod != NULL)
1885430Ssd77468 nvlist_free(mod);
1895430Ssd77468
1905430Ssd77468 /* This is a PCIEX Root Complex */
1915430Ssd77468 if (topo_prop_set_string(rcn, TOPO_PGROUP_PCI, TOPO_PCI_EXCAP,
1925430Ssd77468 TOPO_PROP_IMMUTABLE, PCIEX_ROOT, &err) != 0) {
1935430Ssd77468 topo_mod_dprintf(mp, "Failed to set EXCAP property\n");
1945430Ssd77468 }
1955430Ssd77468 /* BDF of T5440 root complex is constant */
1965430Ssd77468 if (topo_prop_set_string(rcn, TOPO_PGROUP_PCI,
1975430Ssd77468 TOPO_PCI_BDF, TOPO_PROP_IMMUTABLE, CPUBOARD_PX_BDF, &err) != 0) {
1985430Ssd77468 topo_mod_dprintf(mp, "Failed to set EXCAP property\n");
1995430Ssd77468 }
2005430Ssd77468
2015430Ssd77468 /* Make room for children */
202*11583SSurya.Prakki@Sun.COM (void) topo_node_range_create(mp, rcn, PCIEX_BUS, 0, CPUBOARD_MAX);
2035430Ssd77468 return (rcn);
2045430Ssd77468 }
2055430Ssd77468
2065430Ssd77468 /*
2075430Ssd77468 * Create a hostbridge node.
2085430Ssd77468 */
2095430Ssd77468 static tnode_t *
cpuboard_hb_node_create(topo_mod_t * mp,tnode_t * parent,int inst)2105430Ssd77468 cpuboard_hb_node_create(topo_mod_t *mp, tnode_t *parent, int inst)
2115430Ssd77468 {
2125430Ssd77468 int err;
2135430Ssd77468 tnode_t *hbn;
2145430Ssd77468
2155430Ssd77468 topo_mod_dprintf(mp, "cpuboard_hb_node_create: parent=%p, inst=%d\n",
2165430Ssd77468 parent, inst);
2175430Ssd77468
2185430Ssd77468 hbn = cpuboard_node_create(mp, parent, HOSTBRIDGE, inst, NULL);
2195430Ssd77468 if (hbn == NULL) {
2205430Ssd77468 topo_mod_dprintf(mp, "cpuboard_hb_node_create: "
2215430Ssd77468 "cpuboard_node_create() failed.\n");
2225430Ssd77468 return (NULL);
2235430Ssd77468 }
2245430Ssd77468
2255430Ssd77468 /* Inherit parent FRU's label */
2265430Ssd77468 (void) topo_node_fru_set(hbn, NULL, 0, &err);
2275430Ssd77468 (void) topo_node_label_set(hbn, NULL, &err);
2285430Ssd77468
2295430Ssd77468 /* Make room for children */
230*11583SSurya.Prakki@Sun.COM (void) topo_node_range_create(mp, hbn, PCIEX_ROOT, 0, CPUBOARD_MAX);
2315430Ssd77468
2325430Ssd77468 topo_mod_dprintf(mp, "cpuboard_hb_node_create: EXIT hbn=%p\n", hbn);
2335430Ssd77468
2345430Ssd77468 return (hbn);
2355430Ssd77468 }
2365430Ssd77468
2375430Ssd77468 /*
2385430Ssd77468 * Enumerate hostbridge on the cpuboard. Hostbridge and root complex instances
2395430Ssd77468 * match the cpuboard instance.
2405430Ssd77468 */
2415430Ssd77468 int
cpuboard_hb_enum(topo_mod_t * mp,di_node_t dnode,char * rcpath,tnode_t * cpubn,int brd)2427850SVuong.Nguyen@Sun.COM cpuboard_hb_enum(topo_mod_t *mp, di_node_t dnode, char *rcpath,
2437850SVuong.Nguyen@Sun.COM tnode_t *cpubn, int brd)
2445430Ssd77468 {
2455430Ssd77468 int hb;
2465430Ssd77468 int rc;
2475430Ssd77468 tnode_t *hbnode;
2485430Ssd77468 tnode_t *rcnode;
2495430Ssd77468 topo_mod_t *pcimod;
2505430Ssd77468
2515430Ssd77468 topo_mod_dprintf(mp, "cpuboard_hb_enum: brd: %d, cpubn=%p\n",
2525430Ssd77468 brd, cpubn);
2535430Ssd77468
2545430Ssd77468 /* Load the pcibus module. We'll need it later. */
2555430Ssd77468 pcimod = topo_mod_load(mp, PCI_BUS, PCI_BUS_VERS);
2565430Ssd77468 if (pcimod == NULL) {
2575430Ssd77468 topo_mod_dprintf(mp, "can't load pcibus module: %s\n",
2585430Ssd77468 topo_strerror(topo_mod_errno(mp)));
2595430Ssd77468 return (-1);
2605430Ssd77468 }
2615430Ssd77468 hb = rc = brd;
2625430Ssd77468
2635430Ssd77468 /* The root complex exists! */
2645430Ssd77468 topo_mod_dprintf(mp, "declaring "
2655430Ssd77468 "/motherboard=0/cpuboard=%d/hostbridge=%d/"
2665430Ssd77468 "pciexrc=%d\n", brd, hb, rc);
2675430Ssd77468
2685430Ssd77468 /* Create the hostbridge node */
2695430Ssd77468 hbnode = cpuboard_hb_node_create(mp, cpubn, hb);
2705430Ssd77468 if (hbnode == NULL) {
2715430Ssd77468 topo_mod_dprintf(mp,
2725430Ssd77468 "unable to create hbnode: %s\n",
2735430Ssd77468 topo_strerror(topo_mod_errno(mp)));
2745430Ssd77468 topo_mod_unload(pcimod);
2755430Ssd77468 return (-1);
2765430Ssd77468 }
2775430Ssd77468 /* Create the root complex node */
2787850SVuong.Nguyen@Sun.COM rcnode = cpuboard_rc_node_create(mp, hbnode, dnode, rcpath, rc);
2795430Ssd77468 if (rcnode == NULL) {
2805430Ssd77468 topo_mod_dprintf(mp,
2815430Ssd77468 "unable to create rcnode: %s\n",
2825430Ssd77468 topo_strerror(topo_mod_errno(mp)));
2835430Ssd77468 topo_mod_unload(pcimod);
2845430Ssd77468 return (-1);
2855430Ssd77468 }
2865430Ssd77468 /*
2875430Ssd77468 * If dnode not NULL, enumerate pcibus nodes under the root complex.
2885430Ssd77468 * If dnode NULL, skip enumeration. Condition could occur if the RC
2895430Ssd77468 * is assigned to non-control domain.
2905430Ssd77468 */
2915430Ssd77468 if ((dnode != NULL) && topo_mod_enumerate(pcimod, rcnode,
2925430Ssd77468 PCI_BUS, PCIEX_BUS, 0, 255, NULL) != 0) {
2935430Ssd77468 topo_mod_dprintf(mp,
2945430Ssd77468 "error enumerating pcibus: %s\n",
2955430Ssd77468 topo_strerror(topo_mod_errno(mp)));
2965430Ssd77468 topo_mod_unload(pcimod);
2975430Ssd77468 return (-1);
2985430Ssd77468 }
2995430Ssd77468 topo_mod_unload(pcimod);
3005430Ssd77468 return (0);
3015430Ssd77468 }
302