Home | History | Annotate | Download | only in cpuboard
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #include <string.h>
     28 #include <strings.h>
     29 #include <libdevinfo.h>
     30 #include <fm/topo_mod.h>
     31 #include <fm/topo_hc.h>
     32 #include <sys/fm/protocol.h>
     33 #include "cpuboard_topo.h"
     34 
     35 static const topo_pgroup_info_t io_pgroup =
     36 	{ TOPO_PGROUP_IO, TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
     37 static const topo_pgroup_info_t pci_pgroup =
     38 	{ TOPO_PGROUP_PCI, TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
     39 
     40 static tnode_t *
     41 cpuboard_node_create(topo_mod_t *mp, tnode_t *parent, const char *name,
     42     int inst, void *priv)
     43 {
     44 	tnode_t *node;
     45 	nvlist_t *fmri;
     46 	nvlist_t *auth = topo_mod_auth(mp, parent);
     47 
     48 	topo_mod_dprintf(mp, "cpuboard_node_create:\n");
     49 
     50 	if (parent == NULL || inst < 0) {
     51 		return (NULL);
     52 	}
     53 
     54 	/* Create FMRI */
     55 	if ((fmri = topo_mod_hcfmri(mp, parent, FM_HC_SCHEME_VERSION, name,
     56 	    inst, NULL, auth, NULL, NULL, NULL)) == NULL) {
     57 		topo_mod_dprintf(mp, "create of tnode for %s failed: %s",
     58 		    name, topo_strerror(topo_mod_errno(mp)));
     59 		nvlist_free(auth);
     60 		return (NULL);
     61 	}
     62 	nvlist_free(auth);
     63 
     64 	/* Create and bind node  */
     65 	node = topo_node_bind(mp, parent, name, inst, fmri);
     66 	if (node == NULL) {
     67 		nvlist_free(fmri);
     68 		topo_mod_dprintf(mp, "unable to bind root complex: %s\n",
     69 		    topo_strerror(topo_mod_errno(mp)));
     70 		return (NULL); /* mod_errno already set */
     71 	}
     72 
     73 	nvlist_free(fmri);
     74 	topo_node_setspecific(node, priv);
     75 
     76 	return (node);
     77 }
     78 
     79 /*
     80  * cpuboard_rc_node_create()
     81  * Description:
     82  *     Create a root complex node pciexrc
     83  * Parameters:
     84  *     mp: topo module pointer
     85  *     parent: topo parent node of the newly created pciexrc node
     86  *     dnode: Solaris device node of the root complex
     87  *     rcpath: Used to populated the dev property of the topo pciexrc node if
     88  *          the local host does not own the root complex.
     89  */
     90 static tnode_t *
     91 cpuboard_rc_node_create(topo_mod_t *mp, tnode_t *parent, di_node_t dnode,
     92     char *rcpath, int inst)
     93 {
     94 	int err;
     95 	tnode_t *rcn;
     96 	char *dnpath;
     97 	nvlist_t *mod;
     98 
     99 	topo_mod_dprintf(mp, "cpuboard_rc_node_create:\n");
    100 
    101 	rcn = cpuboard_node_create(mp, parent, PCIEX_ROOT, inst, (void *)dnode);
    102 	if (rcn == NULL) {
    103 		return (NULL);
    104 	}
    105 
    106 	/* Inherit parent FRU's label */
    107 	(void) topo_node_fru_set(rcn, NULL, 0, &err);
    108 	(void) topo_node_label_set(rcn, NULL, &err);
    109 
    110 	/*
    111 	 * Set ASRU to be the dev-scheme ASRU
    112 	 */
    113 	if ((dnpath = di_devfs_path(dnode)) != NULL) {
    114 		nvlist_t *fmri;
    115 
    116 		/*
    117 		 * The local host owns the root complex, so use the dev path
    118 		 * from the di_devfs_path(), instead of the passed in rcpath,
    119 		 * to populate the dev property.
    120 		 */
    121 		rcpath = dnpath;
    122 		fmri = topo_mod_devfmri(mp, FM_DEV_SCHEME_VERSION,
    123 		    dnpath, NULL);
    124 		if (fmri == NULL) {
    125 			topo_mod_dprintf(mp,
    126 			    "dev:///%s fmri creation failed.\n",
    127 			    dnpath);
    128 			(void) topo_mod_seterrno(mp, err);
    129 			di_devfs_path_free(dnpath);
    130 			return (NULL);
    131 		}
    132 		if (topo_node_asru_set(rcn, fmri, 0, &err) < 0) {
    133 			topo_mod_dprintf(mp, "topo_node_asru_set failed\n");
    134 			(void) topo_mod_seterrno(mp, err);
    135 			nvlist_free(fmri);
    136 			di_devfs_path_free(dnpath);
    137 			return (NULL);
    138 		}
    139 		nvlist_free(fmri);
    140 	} else {
    141 		topo_mod_dprintf(mp, "NULL di_devfs_path.\n");
    142 	}
    143 
    144 	/*
    145 	 * Set pciexrc properties for root complex nodes
    146 	 */
    147 
    148 	/* Add the io and pci property groups */
    149 	if (topo_pgroup_create(rcn, &io_pgroup, &err) < 0) {
    150 		topo_mod_dprintf(mp, "topo_pgroup_create failed\n");
    151 		di_devfs_path_free(dnpath);
    152 		(void) topo_mod_seterrno(mp, err);
    153 		return (NULL);
    154 	}
    155 	if (topo_pgroup_create(rcn, &pci_pgroup, &err) < 0) {
    156 		topo_mod_dprintf(mp, "topo_pgroup_create failed\n");
    157 		di_devfs_path_free(dnpath);
    158 		(void) topo_mod_seterrno(mp, err);
    159 		return (NULL);
    160 	}
    161 	/* Add the devfs path property */
    162 	if (rcpath) {
    163 		if (topo_prop_set_string(rcn, TOPO_PGROUP_IO, TOPO_IO_DEV,
    164 		    TOPO_PROP_IMMUTABLE, rcpath, &err) != 0) {
    165 			topo_mod_dprintf(mp, "Failed to set DEV property\n");
    166 			(void) topo_mod_seterrno(mp, err);
    167 		}
    168 	}
    169 	if (dnpath) {
    170 		di_devfs_path_free(dnpath);
    171 	}
    172 	/* T5440 device type is always "pciex" */
    173 	if (topo_prop_set_string(rcn, TOPO_PGROUP_IO, TOPO_IO_DEVTYPE,
    174 	    TOPO_PROP_IMMUTABLE, CPUBOARD_PX_DEVTYPE, &err) != 0) {
    175 		topo_mod_dprintf(mp, "Failed to set DEVTYPE property\n");
    176 	}
    177 	/* T5440 driver is always "px" */
    178 	if (topo_prop_set_string(rcn, TOPO_PGROUP_IO, TOPO_IO_DRIVER,
    179 	    TOPO_PROP_IMMUTABLE, CPUBOARD_PX_DRV, &err) != 0) {
    180 		topo_mod_dprintf(mp, "Failed to set DRIVER property\n");
    181 	}
    182 	if ((mod = topo_mod_modfmri(mp, FM_MOD_SCHEME_VERSION, CPUBOARD_PX_DRV))
    183 	    == NULL || topo_prop_set_fmri(rcn, TOPO_PGROUP_IO,
    184 	    TOPO_IO_MODULE, TOPO_PROP_IMMUTABLE, mod,  &err) != 0) {
    185 		topo_mod_dprintf(mp, "Failed to set MODULE property\n");
    186 	}
    187 	if (mod != NULL)
    188 		nvlist_free(mod);
    189 
    190 	/* This is a PCIEX Root Complex */
    191 	if (topo_prop_set_string(rcn, TOPO_PGROUP_PCI, TOPO_PCI_EXCAP,
    192 	    TOPO_PROP_IMMUTABLE, PCIEX_ROOT, &err) != 0) {
    193 		topo_mod_dprintf(mp, "Failed to set EXCAP property\n");
    194 	}
    195 	/* BDF of T5440 root complex is constant */
    196 	if (topo_prop_set_string(rcn, TOPO_PGROUP_PCI,
    197 	    TOPO_PCI_BDF, TOPO_PROP_IMMUTABLE, CPUBOARD_PX_BDF, &err) != 0) {
    198 		topo_mod_dprintf(mp, "Failed to set EXCAP property\n");
    199 	}
    200 
    201 	/* Make room for children */
    202 	(void) topo_node_range_create(mp, rcn, PCIEX_BUS, 0, CPUBOARD_MAX);
    203 	return (rcn);
    204 }
    205 
    206 /*
    207  * Create a hostbridge node.
    208  */
    209 static tnode_t *
    210 cpuboard_hb_node_create(topo_mod_t *mp, tnode_t *parent, int inst)
    211 {
    212 	int err;
    213 	tnode_t *hbn;
    214 
    215 	topo_mod_dprintf(mp, "cpuboard_hb_node_create: parent=%p, inst=%d\n",
    216 	    parent, inst);
    217 
    218 	hbn = cpuboard_node_create(mp, parent, HOSTBRIDGE, inst, NULL);
    219 	if (hbn == NULL) {
    220 		topo_mod_dprintf(mp, "cpuboard_hb_node_create: "
    221 		    "cpuboard_node_create() failed.\n");
    222 		return (NULL);
    223 	}
    224 
    225 	/* Inherit parent FRU's label */
    226 	(void) topo_node_fru_set(hbn, NULL, 0, &err);
    227 	(void) topo_node_label_set(hbn, NULL, &err);
    228 
    229 	/* Make room for children */
    230 	(void) topo_node_range_create(mp, hbn, PCIEX_ROOT, 0, CPUBOARD_MAX);
    231 
    232 	topo_mod_dprintf(mp, "cpuboard_hb_node_create: EXIT hbn=%p\n", hbn);
    233 
    234 	return (hbn);
    235 }
    236 
    237 /*
    238  * Enumerate hostbridge on the cpuboard.  Hostbridge and root complex instances
    239  * match the cpuboard instance.
    240  */
    241 int
    242 cpuboard_hb_enum(topo_mod_t *mp, di_node_t dnode, char *rcpath,
    243     tnode_t *cpubn, int brd)
    244 {
    245 	int hb;
    246 	int rc;
    247 	tnode_t *hbnode;
    248 	tnode_t *rcnode;
    249 	topo_mod_t *pcimod;
    250 
    251 	topo_mod_dprintf(mp, "cpuboard_hb_enum: brd: %d, cpubn=%p\n",
    252 	    brd, cpubn);
    253 
    254 	/* Load the pcibus module. We'll need it later. */
    255 	pcimod = topo_mod_load(mp, PCI_BUS, PCI_BUS_VERS);
    256 	if (pcimod == NULL) {
    257 		topo_mod_dprintf(mp, "can't load pcibus module: %s\n",
    258 		    topo_strerror(topo_mod_errno(mp)));
    259 		return (-1);
    260 	}
    261 	hb = rc = brd;
    262 
    263 	/* The root complex exists! */
    264 	topo_mod_dprintf(mp, "declaring "
    265 	    "/motherboard=0/cpuboard=%d/hostbridge=%d/"
    266 	    "pciexrc=%d\n", brd, hb, rc);
    267 
    268 	/* Create the hostbridge node */
    269 	hbnode = cpuboard_hb_node_create(mp, cpubn, hb);
    270 	if (hbnode == NULL) {
    271 		topo_mod_dprintf(mp,
    272 		    "unable to create hbnode: %s\n",
    273 		    topo_strerror(topo_mod_errno(mp)));
    274 		topo_mod_unload(pcimod);
    275 		return (-1);
    276 	}
    277 	/* Create the root complex node */
    278 	rcnode = cpuboard_rc_node_create(mp, hbnode, dnode, rcpath, rc);
    279 	if (rcnode == NULL) {
    280 		topo_mod_dprintf(mp,
    281 		    "unable to create rcnode: %s\n",
    282 		    topo_strerror(topo_mod_errno(mp)));
    283 		topo_mod_unload(pcimod);
    284 		return (-1);
    285 	}
    286 	/*
    287 	 * If dnode not NULL, enumerate pcibus nodes under the root complex.
    288 	 * If dnode NULL, skip enumeration.  Condition could occur if the RC
    289 	 * is assigned to non-control domain.
    290 	 */
    291 	if ((dnode != NULL) && topo_mod_enumerate(pcimod, rcnode,
    292 	    PCI_BUS, PCIEX_BUS, 0, 255, NULL) != 0) {
    293 		topo_mod_dprintf(mp,
    294 		    "error enumerating pcibus: %s\n",
    295 		    topo_strerror(topo_mod_errno(mp)));
    296 		topo_mod_unload(pcimod);
    297 		return (-1);
    298 	}
    299 	topo_mod_unload(pcimod);
    300 	return (0);
    301 }
    302