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