129493bdvn/*
229493bdvn * CDDL HEADER START
329493bdvn *
429493bdvn * The contents of this file are subject to the terms of the
529493bdvn * Common Development and Distribution License (the "License").
629493bdvn * You may not use this file except in compliance with the License.
729493bdvn *
829493bdvn * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
929493bdvn * or http://www.opensolaris.org/os/licensing.
1029493bdvn * See the License for the specific language governing permissions
1129493bdvn * and limitations under the License.
1229493bdvn *
1329493bdvn * When distributing Covered Code, include this CDDL HEADER in each
1429493bdvn * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1529493bdvn * If applicable, add the following below this CDDL HEADER, with the
1629493bdvn * fields enclosed by brackets "[]" replaced with your own identifying
1729493bdvn * information: Portions Copyright [yyyy] [name of copyright owner]
1829493bdvn *
1929493bdvn * CDDL HEADER END
2029493bdvn */
2129493bdvn
2229493bdvn/*
2329493bdvn * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
2429493bdvn * Use is subject to license terms.
2529493bdvn */
2629493bdvn
2729493bdvn#include <string.h>
2829493bdvn#include <strings.h>
2929493bdvn#include <umem.h>
3029493bdvn#include <sys/mdesc.h>
3129493bdvn#include <sys/systeminfo.h>
3229493bdvn#include <sys/fm/ldom.h>
3329493bdvn
3429493bdvn#include <hb_mdesc.h>
3529493bdvn
3629493bdvn#include "hb_rcid.h"
3729493bdvn
3829493bdvnstatic void *
3929493bdvnhb_alloc(size_t size)
4029493bdvn{
4129493bdvn	return (umem_alloc(size, UMEM_DEFAULT));
4229493bdvn}
4329493bdvn
4429493bdvnstatic void
4529493bdvnhb_free(void *data, size_t size)
4629493bdvn{
4729493bdvn	umem_free(data, size);
4829493bdvn}
4929493bdvn
5029493bdvn/*
5129493bdvn * hb_find_hb()
5229493bdvn * Description:
5329493bdvn *     Return the pointer of hostbridge entry
5429493bdvn */
5529493bdvnmd_hb_t *
5629493bdvnhb_find_hb(md_info_t *phbmd, int hbid) {
5729493bdvn	int i;
5829493bdvn	md_hb_t *phb;
5929493bdvn
6029493bdvn	/* search the processor based on the physical id */
6129493bdvn	for (i = 0, phb = phbmd->hbs; i < phbmd->nhbs; i++, phb++) {
6229493bdvn		if (phb->rcs != NULL && phb->id == hbid) {
6329493bdvn			return (phb);
6429493bdvn		}
6529493bdvn	}
6629493bdvn
6729493bdvn	return (NULL);
6829493bdvn}
6929493bdvn
7029493bdvn/*
7129493bdvn * hb_rc_init()
7229493bdvn * Description:
7329493bdvn *     Read the hostbridge/pciexrc information from the MD
7429493bdvn *     The hostbridge/pciexrc information is not specified in the PRI of
7529493bdvn *     the existing sun4v platforms, the enumerator assumes there is only
7629493bdvn *     one hostbridge and its physical id is 0. It will create all the
7729493bdvn *     pciexrc nodes under the topo node hostbridge=0.
7829493bdvn */
7929493bdvnstatic int
8029493bdvnhb_rc_init(topo_mod_t *mod, md_t *mdp, md_info_t *hbmdp)
8129493bdvn{
8229493bdvn	int i, rc;
8329493bdvn	int id, nnode, nio, nrcs;
8429493bdvn	char *s = NULL;
8529493bdvn	uint64_t x;
8629493bdvn	mde_cookie_t *listp;
8729493bdvn	md_hb_t *hbp;
8829493bdvn	char platform[MAXNAMELEN];
8929493bdvn
9029493bdvn	bzero(hbmdp, sizeof (md_info_t));
9129493bdvn	nnode = md_node_count(mdp);
9229493bdvn	listp = topo_mod_zalloc(mod, sizeof (mde_cookie_t) * nnode);
9329493bdvn
9429493bdvn	/* find the pciex bus nodes */
9529493bdvn	nio = md_scan_dag(mdp,
9629493bdvn	    MDE_INVAL_ELEM_COOKIE,
9729493bdvn	    md_find_name(mdp, MD_STR_IODEVICE),
9829493bdvn	    md_find_name(mdp, "fwd"),
9929493bdvn	    listp);
10029493bdvn	if (nio <= 0) {
10129493bdvn		topo_mod_dprintf(mod, "iodevice nodes not found\n");
10229493bdvn		topo_mod_free(mod, listp, sizeof (mde_cookie_t) * nnode);
10329493bdvn		return (-1);
10429493bdvn	}
10529493bdvn	topo_mod_dprintf(mod, "Found %d %s nodes\n", nio, MD_STR_IODEVICE);
10629493bdvn
10729493bdvn	for (i = 0, nrcs = 0; i < nio; i++) {
10829493bdvn		rc = md_get_prop_str(mdp, listp[i], MD_STR_DEVICE_TYPE, &s);
10929493bdvn		if ((rc == 0) && (s != NULL) && (strcmp(s, MD_STR_PCIEX) == 0))
11029493bdvn			nrcs++;
11129493bdvn	}
11229493bdvn	topo_mod_dprintf(mod, "Found %d pciex buses\n", nrcs);
11329493bdvn	if (nrcs == 0) {
11429493bdvn		topo_mod_dprintf(mod, "pciex nodes not found\n");
11529493bdvn		topo_mod_free(mod, listp, sizeof (mde_cookie_t) * nnode);
11629493bdvn		return (-1);
11729493bdvn	}
11829493bdvn
11929493bdvn	platform[0] = '\0';
12029493bdvn	(void) sysinfo(SI_PLATFORM, platform, sizeof (platform));
12129493bdvn
12229493bdvn	/*
12329493bdvn	 * All existing sun4v platforms have only one hostdridge.
12429493bdvn	 */
12529493bdvn	hbmdp->shbs = hbmdp->nhbs = 1;
12629493bdvn	hbp = topo_mod_zalloc(mod, sizeof (md_hb_t) * hbmdp->nhbs);
12729493bdvn	hbp->id = 0;
12829493bdvn	hbmdp->hbs = hbp;
12929493bdvn
13029493bdvn	hbp->srcs = nrcs;
13129493bdvn	hbp->rcs = topo_mod_zalloc(mod, sizeof (md_rc_t) * nrcs);
13229493bdvn	hbp->nrcs = 0;
13329493bdvn	for (i = 0, nrcs = 0; i < nio; i++) {
13429493bdvn		rc = md_get_prop_str(mdp, listp[i], MD_STR_DEVICE_TYPE, &s);
13529493bdvn		if ((rc != 0) || s == NULL || strcmp(s, MD_STR_PCIEX) != 0)
13629493bdvn			continue;
13729493bdvn
13829493bdvn		hbp->rcs[nrcs].id = -1;		/* invalidate the entry */
13929493bdvn
14029493bdvn		/* bus address */
14129493bdvn		if (md_get_prop_val(mdp, listp[i], MD_STR_CFGHDL, &x) < 0) {
14229493bdvn			nrcs++;
14329493bdvn			continue;
14429493bdvn		}
14529493bdvn		hbp->rcs[nrcs].cfg_handle = x;
14629493bdvn		topo_mod_dprintf(mod, "Found rc=%d ba=%llx\n", nrcs, x);
14729493bdvn
14829493bdvn		/* Assign the physical id of the pciexrc */
14929493bdvn		if ((id = hb_find_rc_pid(platform, x)) >= 0)
15029493bdvn			hbp->rcs[nrcs].id = id;
15129493bdvn		else
15229493bdvn			hbp->rcs[nrcs].id = hbp->nrcs;
15329493bdvn
15429493bdvn		nrcs++;
15529493bdvn		hbp->nrcs++;
15629493bdvn	}
15729493bdvn
15829493bdvn	topo_mod_free(mod, listp, sizeof (mde_cookie_t) * nnode);
15929493bdvn
16029493bdvn	return (0);
16129493bdvn}
16229493bdvn
16329493bdvn/*
16429493bdvn * Get the info. of the hb and rc from the PRI/MD
16529493bdvn */
16629493bdvnint
16729493bdvnhb_mdesc_init(topo_mod_t *mod, md_info_t *phbmd)
16829493bdvn{
16929493bdvn	int rc = -1;
17029493bdvn	md_t *mdp;
17129493bdvn	ssize_t bufsiz = 0;
17229493bdvn	uint64_t *bufp;
1732535165Vuong Nguyen	uint32_t type = 0;
17429493bdvn	ldom_hdl_t *lhp;
17529493bdvn
17629493bdvn	/* get the PRI/MD */
17729493bdvn	if ((lhp = ldom_init(hb_alloc, hb_free)) == NULL) {
17829493bdvn		topo_mod_dprintf(mod, "ldom_init() failed\n");
17929493bdvn		return (topo_mod_seterrno(mod, EMOD_NOMEM));
18029493bdvn	}
1812535165Vuong Nguyen
1822535165Vuong Nguyen	(void) ldom_get_type(lhp, &type);
1832535165Vuong Nguyen	if ((type & LDOM_TYPE_CONTROL) != 0) {
1842535165Vuong Nguyen		bufsiz = ldom_get_core_md(lhp, &bufp);
1852535165Vuong Nguyen	} else {
1862535165Vuong Nguyen		bufsiz = ldom_get_local_md(lhp, &bufp);
1872535165Vuong Nguyen	}
1882535165Vuong Nguyen	if (bufsiz <= 0) {
18929493bdvn		topo_mod_dprintf(mod, "failed to get the PRI/MD\n");
19029493bdvn		ldom_fini(lhp);
19129493bdvn		return (-1);
19229493bdvn	}
19329493bdvn
19429493bdvn	if ((mdp = md_init_intern(bufp, hb_alloc, hb_free)) == NULL ||
19529493bdvn	    md_node_count(mdp) <= 0) {
19629493bdvn		hb_free(bufp, (size_t)bufsiz);
19729493bdvn		ldom_fini(lhp);
19829493bdvn		return (-1);
19929493bdvn	}
20029493bdvn
20129493bdvn	rc = hb_rc_init(mod, mdp, phbmd);
20229493bdvn
20329493bdvn	hb_free(bufp, (size_t)bufsiz);
20429493bdvn	(void) md_fini(mdp);
20529493bdvn	ldom_fini(lhp);
20629493bdvn
20729493bdvn	return (rc);
20829493bdvn}
20929493bdvn
21029493bdvnvoid
21129493bdvnhb_mdesc_fini(topo_mod_t *mod, md_info_t *hbmdp)
21229493bdvn{
21329493bdvn	int i;
21429493bdvn	md_hb_t *hbp;
21529493bdvn
21629493bdvn	if (hbmdp->hbs == NULL)
21729493bdvn		return;
21829493bdvn
21929493bdvn	for (i = 0, hbp = hbmdp->hbs; i < hbmdp->nhbs; i++, hbp++) {
22029493bdvn		if (hbp->rcs == NULL)
22129493bdvn			continue;
22229493bdvn		topo_mod_free(mod, hbp->rcs, hbp->srcs * sizeof (md_rc_t));
22329493bdvn	}
22429493bdvn	topo_mod_free(mod, hbmdp->hbs, hbmdp->shbs * sizeof (md_hb_t));
22529493bdvn
22629493bdvn}
227