Home | History | Annotate | Download | only in hostbridge
      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 2008 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 <umem.h>
     30 #include <sys/mdesc.h>
     31 #include <sys/systeminfo.h>
     32 #include <sys/fm/ldom.h>
     33 
     34 #include <hb_mdesc.h>
     35 
     36 #include "hb_rcid.h"
     37 
     38 static void *
     39 hb_alloc(size_t size)
     40 {
     41 	return (umem_alloc(size, UMEM_DEFAULT));
     42 }
     43 
     44 static void
     45 hb_free(void *data, size_t size)
     46 {
     47 	umem_free(data, size);
     48 }
     49 
     50 /*
     51  * hb_find_hb()
     52  * Description:
     53  *     Return the pointer of hostbridge entry
     54  */
     55 md_hb_t *
     56 hb_find_hb(md_info_t *phbmd, int hbid) {
     57 	int i;
     58 	md_hb_t *phb;
     59 
     60 	/* search the processor based on the physical id */
     61 	for (i = 0, phb = phbmd->hbs; i < phbmd->nhbs; i++, phb++) {
     62 		if (phb->rcs != NULL && phb->id == hbid) {
     63 			return (phb);
     64 		}
     65 	}
     66 
     67 	return (NULL);
     68 }
     69 
     70 /*
     71  * hb_rc_init()
     72  * Description:
     73  *     Read the hostbridge/pciexrc information from the MD
     74  *     The hostbridge/pciexrc information is not specified in the PRI of
     75  *     the existing sun4v platforms, the enumerator assumes there is only
     76  *     one hostbridge and its physical id is 0. It will create all the
     77  *     pciexrc nodes under the topo node hostbridge=0.
     78  */
     79 static int
     80 hb_rc_init(topo_mod_t *mod, md_t *mdp, md_info_t *hbmdp)
     81 {
     82 	int i, rc;
     83 	int id, nnode, nio, nrcs;
     84 	char *s = NULL;
     85 	uint64_t x;
     86 	mde_cookie_t *listp;
     87 	md_hb_t *hbp;
     88 	char platform[MAXNAMELEN];
     89 
     90 	bzero(hbmdp, sizeof (md_info_t));
     91 	nnode = md_node_count(mdp);
     92 	listp = topo_mod_zalloc(mod, sizeof (mde_cookie_t) * nnode);
     93 
     94 	/* find the pciex bus nodes */
     95 	nio = md_scan_dag(mdp,
     96 	    MDE_INVAL_ELEM_COOKIE,
     97 	    md_find_name(mdp, MD_STR_IODEVICE),
     98 	    md_find_name(mdp, "fwd"),
     99 	    listp);
    100 	if (nio <= 0) {
    101 		topo_mod_dprintf(mod, "iodevice nodes not found\n");
    102 		topo_mod_free(mod, listp, sizeof (mde_cookie_t) * nnode);
    103 		return (-1);
    104 	}
    105 	topo_mod_dprintf(mod, "Found %d %s nodes\n", nio, MD_STR_IODEVICE);
    106 
    107 	for (i = 0, nrcs = 0; i < nio; i++) {
    108 		rc = md_get_prop_str(mdp, listp[i], MD_STR_DEVICE_TYPE, &s);
    109 		if ((rc == 0) && (s != NULL) && (strcmp(s, MD_STR_PCIEX) == 0))
    110 			nrcs++;
    111 	}
    112 	topo_mod_dprintf(mod, "Found %d pciex buses\n", nrcs);
    113 	if (nrcs == 0) {
    114 		topo_mod_dprintf(mod, "pciex nodes not found\n");
    115 		topo_mod_free(mod, listp, sizeof (mde_cookie_t) * nnode);
    116 		return (-1);
    117 	}
    118 
    119 	platform[0] = '\0';
    120 	(void) sysinfo(SI_PLATFORM, platform, sizeof (platform));
    121 
    122 	/*
    123 	 * All existing sun4v platforms have only one hostdridge.
    124 	 */
    125 	hbmdp->shbs = hbmdp->nhbs = 1;
    126 	hbp = topo_mod_zalloc(mod, sizeof (md_hb_t) * hbmdp->nhbs);
    127 	hbp->id = 0;
    128 	hbmdp->hbs = hbp;
    129 
    130 	hbp->srcs = nrcs;
    131 	hbp->rcs = topo_mod_zalloc(mod, sizeof (md_rc_t) * nrcs);
    132 	hbp->nrcs = 0;
    133 	for (i = 0, nrcs = 0; i < nio; i++) {
    134 		rc = md_get_prop_str(mdp, listp[i], MD_STR_DEVICE_TYPE, &s);
    135 		if ((rc != 0) || s == NULL || strcmp(s, MD_STR_PCIEX) != 0)
    136 			continue;
    137 
    138 		hbp->rcs[nrcs].id = -1;		/* invalidate the entry */
    139 
    140 		/* bus address */
    141 		if (md_get_prop_val(mdp, listp[i], MD_STR_CFGHDL, &x) < 0) {
    142 			nrcs++;
    143 			continue;
    144 		}
    145 		hbp->rcs[nrcs].cfg_handle = x;
    146 		topo_mod_dprintf(mod, "Found rc=%d ba=%llx\n", nrcs, x);
    147 
    148 		/* Assign the physical id of the pciexrc */
    149 		if ((id = hb_find_rc_pid(platform, x)) >= 0)
    150 			hbp->rcs[nrcs].id = id;
    151 		else
    152 			hbp->rcs[nrcs].id = hbp->nrcs;
    153 
    154 		nrcs++;
    155 		hbp->nrcs++;
    156 	}
    157 
    158 	topo_mod_free(mod, listp, sizeof (mde_cookie_t) * nnode);
    159 
    160 	return (0);
    161 }
    162 
    163 /*
    164  * Get the info. of the hb and rc from the PRI/MD
    165  */
    166 int
    167 hb_mdesc_init(topo_mod_t *mod, md_info_t *phbmd)
    168 {
    169 	int rc = -1;
    170 	md_t *mdp;
    171 	ssize_t bufsiz = 0;
    172 	uint64_t *bufp;
    173 	uint32_t type = 0;
    174 	ldom_hdl_t *lhp;
    175 
    176 	/* get the PRI/MD */
    177 	if ((lhp = ldom_init(hb_alloc, hb_free)) == NULL) {
    178 		topo_mod_dprintf(mod, "ldom_init() failed\n");
    179 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
    180 	}
    181 
    182 	(void) ldom_get_type(lhp, &type);
    183 	if ((type & LDOM_TYPE_CONTROL) != 0) {
    184 		bufsiz = ldom_get_core_md(lhp, &bufp);
    185 	} else {
    186 		bufsiz = ldom_get_local_md(lhp, &bufp);
    187 	}
    188 	if (bufsiz <= 0) {
    189 		topo_mod_dprintf(mod, "failed to get the PRI/MD\n");
    190 		ldom_fini(lhp);
    191 		return (-1);
    192 	}
    193 
    194 	if ((mdp = md_init_intern(bufp, hb_alloc, hb_free)) == NULL ||
    195 	    md_node_count(mdp) <= 0) {
    196 		hb_free(bufp, (size_t)bufsiz);
    197 		ldom_fini(lhp);
    198 		return (-1);
    199 	}
    200 
    201 	rc = hb_rc_init(mod, mdp, phbmd);
    202 
    203 	hb_free(bufp, (size_t)bufsiz);
    204 	(void) md_fini(mdp);
    205 	ldom_fini(lhp);
    206 
    207 	return (rc);
    208 }
    209 
    210 void
    211 hb_mdesc_fini(topo_mod_t *mod, md_info_t *hbmdp)
    212 {
    213 	int i;
    214 	md_hb_t *hbp;
    215 
    216 	if (hbmdp->hbs == NULL)
    217 		return;
    218 
    219 	for (i = 0, hbp = hbmdp->hbs; i < hbmdp->nhbs; i++, hbp++) {
    220 		if (hbp->rcs == NULL)
    221 			continue;
    222 		topo_mod_free(mod, hbp->rcs, hbp->srcs * sizeof (md_rc_t));
    223 	}
    224 	topo_mod_free(mod, hbmdp->hbs, hbmdp->shbs * sizeof (md_hb_t));
    225 
    226 }
    227