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 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <string.h> 30 #include <fm/topo_mod.h> 31 #include <libdevinfo.h> 32 #include <sys/param.h> 33 #include <sys/systeminfo.h> 34 35 #include <hb_sun4.h> 36 #include <util.h> 37 #include <hostbridge.h> 38 #include <pcibus.h> 39 #include <did.h> 40 41 busorrc_t * 42 busorrc_new(topo_mod_t *mod, const char *bus_addr, di_node_t di) 43 { 44 busorrc_t *pp; 45 char *comma; 46 char *bac; 47 int e; 48 49 if ((pp = topo_mod_zalloc(mod, sizeof (busorrc_t))) == NULL) 50 return (NULL); 51 pp->br_din = di; 52 bac = topo_mod_strdup(mod, bus_addr); 53 if ((comma = strchr(bac, ',')) != NULL) 54 *comma = '\0'; 55 pp->br_ba_bc = strtonum(mod, bac, &e); 56 if (e < 0) { 57 topo_mod_dprintf(mod, 58 "Trouble interpreting bus_addr before comma.\n"); 59 if (comma != NULL) 60 *comma = ','; 61 topo_mod_strfree(mod, bac); 62 topo_mod_free(mod, pp, sizeof (busorrc_t)); 63 return (NULL); 64 } 65 if (comma == NULL) { 66 pp->br_ba_ac = 0; 67 topo_mod_strfree(mod, bac); 68 return (pp); 69 } 70 pp->br_ba_ac = strtonum(mod, comma + 1, &e); 71 if (e < 0) { 72 topo_mod_dprintf(mod, 73 "Trouble interpreting bus_addr after comma.\n"); 74 *comma = ','; 75 topo_mod_strfree(mod, bac); 76 topo_mod_free(mod, pp, sizeof (busorrc_t)); 77 return (NULL); 78 } 79 *comma = ','; 80 topo_mod_strfree(mod, bac); 81 return (pp); 82 } 83 84 void 85 busorrc_insert(topo_mod_t *mod, busorrc_t **head, busorrc_t *new) 86 { 87 busorrc_t *ppci, *pci; 88 89 topo_mod_dprintf(mod, 90 "inserting (%x,%x)\n", new->br_ba_bc, new->br_ba_ac); 91 92 /* No entries yet? */ 93 if (*head == NULL) { 94 *head = new; 95 return; 96 } 97 98 ppci = NULL; 99 pci = *head; 100 101 while (pci != NULL) { 102 if (new->br_ba_ac == pci->br_ba_ac) 103 if (new->br_ba_bc < pci->br_ba_bc) 104 break; 105 if (new->br_ba_ac < pci->br_ba_ac) 106 break; 107 ppci = pci; 108 pci = pci->br_nextbus; 109 } 110 if (ppci == NULL) { 111 new->br_nextbus = pci; 112 pci->br_prevbus = new; 113 *head = new; 114 } else { 115 new->br_nextbus = ppci->br_nextbus; 116 if (new->br_nextbus != NULL) 117 new->br_nextbus->br_prevbus = new; 118 ppci->br_nextbus = new; 119 new->br_prevbus = ppci; 120 } 121 } 122 123 int 124 busorrc_add(topo_mod_t *mod, busorrc_t **list, di_node_t n) 125 { 126 busorrc_t *nb; 127 char *ba; 128 129 topo_mod_dprintf(mod, "busorrc_add\n"); 130 ba = di_bus_addr(n); 131 if (ba == NULL || 132 (nb = busorrc_new(mod, ba, n)) == NULL) { 133 topo_mod_dprintf(mod, "busorrc_new() failed.\n"); 134 return (-1); 135 } 136 busorrc_insert(mod, list, nb); 137 return (0); 138 } 139 140 void 141 busorrc_free(topo_mod_t *mod, busorrc_t *pb) 142 { 143 if (pb == NULL) 144 return; 145 busorrc_free(mod, pb->br_nextbus); 146 topo_mod_free(mod, pb, sizeof (busorrc_t)); 147 } 148 149 tnode_t * 150 hb_process(topo_mod_t *mod, tnode_t *ptn, topo_instance_t hbi, 151 topo_instance_t bi, di_node_t bn, did_t *hbdid) 152 { 153 tnode_t *hb; 154 155 if ((hb = pcihostbridge_declare(mod, ptn, bn, hbi)) == NULL) 156 return (NULL); 157 if (topo_mod_enumerate(mod, hb, PCI_BUS, PCI_BUS, bi, bi, hbdid) == 0) 158 return (hb); 159 160 topo_node_unbind(hb); 161 162 return (NULL); 163 } 164 165 tnode_t * 166 rc_process(topo_mod_t *mod, tnode_t *ptn, topo_instance_t rci, di_node_t bn) 167 { 168 tnode_t *rc; 169 170 if ((rc = pciexrc_declare(mod, ptn, bn, rci)) == NULL) 171 return (NULL); 172 if (topo_mod_enumerate(mod, 173 rc, PCI_BUS, PCIEX_BUS, 0, MAX_HB_BUSES, NULL) == 0) 174 return (rc); 175 176 topo_node_unbind(rc); 177 178 return (NULL); 179 } 180 181 /* 182 * declare_exbuses() assumes the elements in the provided busorrc list 183 * are sorted thusly: 184 * 185 * (Hostbridge #0, Root Complex #0, ExBus #0) 186 * (Hostbridge #0, Root Complex #0, ExBus #1) 187 * ... 188 * (Hostbridge #0, Root Complex #0, ExBus #(buses/rc)) 189 * (Hostbridge #0, Root Complex #1, ExBus #0) 190 * ... 191 * (Hostbridge #0, Root Complex #1, ExBus #(buses/rc)) 192 * ... 193 * ... 194 * (Hostbridge #0, Root Complex #(rcs/hostbridge), ExBus #(buses/rc)) 195 * (Hostbridge #1, Root Complex #0, ExBus #0) 196 * ... 197 * ... 198 * ... 199 * ... 200 * (Hostbridge #nhb, Root Complex #(rcs/hostbridge), ExBus #(buses/rc)) 201 */ 202 int 203 declare_exbuses(topo_mod_t *mod, busorrc_t *list, tnode_t *ptn, int nhb, 204 int nrc) 205 { 206 int err = 0; 207 tnode_t **rcs; 208 tnode_t **hb; 209 busorrc_t *p; 210 int br, rc; 211 212 /* 213 * Allocate an array to point at the hostbridge tnode_t pointers. 214 */ 215 if ((hb = topo_mod_zalloc(mod, nhb * sizeof (tnode_t *))) == NULL) 216 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 217 218 /* 219 * Allocate an array to point at the root complex tnode_t pointers. 220 */ 221 if ((rcs = topo_mod_zalloc(mod, nrc * sizeof (tnode_t *))) == NULL) { 222 topo_mod_free(mod, hb, nhb * sizeof (tnode_t *)); 223 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 224 } 225 226 br = rc = 0; 227 for (p = list; p != NULL; p = p->br_nextbus) { 228 topo_mod_dprintf(mod, 229 "declaring (%x,%x)\n", p->br_ba_bc, p->br_ba_ac); 230 231 if (did_create(mod, p->br_din, 0, br, rc, rc) == NULL) { 232 err = -1; 233 break; 234 } 235 236 if (hb[br] == NULL) { 237 hb[br] = pciexhostbridge_declare(mod, ptn, p->br_din, 238 br); 239 if (hb[br] == NULL) { 240 err = -1; 241 break; 242 } 243 } 244 if (rcs[rc] == NULL) { 245 rcs[rc] = rc_process(mod, hb[br], rc, p->br_din); 246 if (rcs[rc] == NULL) { 247 err = -1; 248 break; 249 } 250 } else { 251 if (topo_mod_enumerate(mod, 252 rcs[rc], PCI_BUS, PCIEX_BUS, 0, MAX_HB_BUSES, 253 NULL) < 0) { 254 err = -1; 255 break; 256 } 257 } 258 rc++; 259 if (rc == nrc) { 260 rc = 0; 261 br++; 262 if (br == nhb) 263 br = 0; 264 } 265 } 266 267 if (err != 0) { 268 int i; 269 270 for (i = 0; i < nhb; ++i) 271 topo_node_unbind(hb[br]); 272 for (i = 0; i < nrc; ++i) 273 topo_node_unbind(rcs[rc]); 274 } 275 276 topo_mod_free(mod, rcs, nrc * sizeof (tnode_t *)); 277 topo_mod_free(mod, hb, nhb * sizeof (tnode_t *)); 278 279 return (err); 280 } 281 282 /* 283 * declare_buses() assumes the elements in the provided busorrc list 284 * are sorted thusly: 285 * 286 * (Hostbridge #0, Bus #0) 287 * (Hostbridge #1, Bus #0) 288 * ... 289 * (Hostbridge #nhb, Bus #0) 290 * (Hostbridge #0, Bus #1) 291 * ... 292 * ... 293 * (Hostbridge #nhb, Bus #(buses/hostbridge)) 294 */ 295 int 296 declare_buses(topo_mod_t *mod, busorrc_t *list, tnode_t *ptn, int nhb) 297 { 298 int err = 0; 299 busorrc_t *p; 300 tnode_t **hb; 301 did_t *link; 302 int br, bus; 303 304 /* 305 * Allocate an array to point at the hostbridge tnode_t pointers. 306 */ 307 if ((hb = topo_mod_zalloc(mod, nhb * sizeof (tnode_t *))) == NULL) 308 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 309 310 br = bus = 0; 311 for (p = list; p != NULL; p = p->br_nextbus) { 312 topo_mod_dprintf(mod, 313 "declaring (%x,%x)\n", p->br_ba_bc, p->br_ba_ac); 314 315 if ((link = 316 did_create(mod, p->br_din, 0, br, NO_RC, bus)) == NULL) { 317 err = -1; 318 break; 319 } 320 321 if (hb[br] == NULL) { 322 hb[br] = hb_process(mod, ptn, br, bus, p->br_din, link); 323 if (hb[br] == NULL) { 324 err = -1; 325 break; 326 } 327 } else { 328 did_link_set(mod, hb[br], link); 329 if (topo_mod_enumerate(mod, 330 hb[br], PCI_BUS, PCI_BUS, bus, bus, link) < 0) { 331 err = -1; 332 break; 333 } 334 } 335 br++; 336 if (br == nhb) { 337 br = 0; 338 bus++; 339 } 340 } 341 342 if (err != 0) { 343 int i; 344 345 for (i = 0; i < nhb; ++i) 346 topo_node_unbind(hb[br]); 347 } 348 349 topo_mod_free(mod, hb, nhb * sizeof (tnode_t *)); 350 return (err); 351 } 352