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 /* 28 * i86pc Generic hostbridge/pciex/pci enumerator 29 * 30 * hostbridge/pciexrc/pcibus topo nodes are created per SMBIOS type 138 31 * (SUN_OEM_PCIEXRC) records. Each type 138 record can either represent 32 * a hostbridge or a pciexrc/pcibus determined by whether it points to 33 * a baseboard record or another type 138 record. 34 * 35 * x86pi_gen_hbr() is called when a new hostbridge node needs to be created.. 36 * It then searches all the type 138 records that connected to it. For each 37 * of the records, bdf is compared to find a matching di_node. If the 38 * di_node is a pciex root port, a pciexrc (bad name!) node will be created. 39 * When pciexrc creation is done, or the di_node is a pcibus, in either 40 * case the pcibus module will loaded to enumerate pciexbus/pcibus etc. 41 * 42 * The enumeration uses did routines heavily, which requires a did hash 43 * pointer stored in x86pi's module-specific area. 44 */ 45 46 #include <sys/types.h> 47 #include <strings.h> 48 #include <fm/topo_mod.h> 49 #include <fm/topo_hc.h> 50 #include <sys/systeminfo.h> 51 #include <sys/smbios_impl.h> 52 #include <sys/fm/protocol.h> 53 #include <x86pi_impl.h> 54 #include <did.h> 55 #include <did_impl.h> 56 #include <did_props.h> 57 #include <hostbridge.h> 58 59 #define PCI_ENUM "pcibus" 60 #define PCI_ENUMR_VERS 1 61 #define MAX_HB_BUSES 255 62 63 extern txprop_t RC_common_props[], HB_common_props[], ExHB_common_props[]; 64 extern int RC_propcnt, HB_propcnt, ExHB_propcnt; 65 66 static topo_mod_t *pcimp = NULL; 67 68 int 69 x86pi_hbr_enum_init(topo_mod_t *mod) 70 { 71 did_hash_t *tab = (did_hash_t *)topo_mod_getspecific(mod); 72 const char *f = "x86pi_hbr_enum_init"; 73 74 if (tab == NULL && did_hash_init(mod) < 0) { 75 topo_mod_dprintf(mod, "%s: did_hash_init() failed.\n", f); 76 return (-1); 77 } 78 79 if (pcimp == NULL && 80 (pcimp = topo_mod_load(mod, PCI_ENUM, PCI_ENUMR_VERS)) 81 == NULL) { 82 topo_mod_dprintf(mod, 83 "%s: %s enumerator could not load %s.\n", 84 f, HOSTBRIDGE, PCI_ENUM); 85 did_hash_fini(mod); 86 return (-1); 87 } 88 89 return (0); 90 } 91 92 void 93 x86pi_hbr_enum_fini(topo_mod_t *mod) 94 { 95 did_hash_fini(mod); 96 if (pcimp != NULL) { 97 topo_mod_unload(pcimp); 98 pcimp = NULL; 99 } 100 } 101 102 static int 103 pciex_process(topo_mod_t *mod, tnode_t *tn_hbr, di_node_t rcn, 104 topo_instance_t rci) 105 { 106 did_t *did; 107 int rv; 108 tnode_t *tn_rc; 109 x86pi_hcfmri_t hcfmri = {0}; 110 tnode_t *tn_bb = topo_node_parent(tn_hbr); 111 const char *f = "pciexrc_process"; 112 113 if ((did = did_create(mod, rcn, topo_node_instance(tn_bb), 114 topo_node_instance(tn_hbr), rci, TRUST_BDF)) == NULL) 115 return (NULL); 116 117 did_markrc(did); 118 119 /* 120 * Let did set the hostbridge properties excluding FRU and label. 121 */ 122 (void) did_props_set(tn_hbr, did, ExHB_common_props, ExHB_propcnt - 2); 123 124 if (topo_node_range_create(mod, tn_hbr, PCIEX_ROOT, 0, 125 MAX_HB_BUSES) != 0 && topo_mod_errno(mod) != EMOD_NODE_DUP) { 126 topo_mod_dprintf(mod, 127 "%s: create child range for %s failed: %s\n", 128 f, PCIEX_ROOT, topo_mod_errmsg(mod)); 129 return (-1); 130 } 131 132 hcfmri.hc_name = PCIEX_ROOT; 133 hcfmri.instance = rci; 134 rv = x86pi_enum_generic(mod, &hcfmri, tn_hbr, tn_hbr, &tn_rc, 0); 135 if (rv != 0) { 136 topo_mod_dprintf(mod, "%s: failed to create %s = %d\n", 137 f, PCIEX_ROOT, rci); 138 return (-1); 139 } 140 141 /* 142 * pcibus enumerator requires di_node_t be set in node specific 143 */ 144 topo_node_setspecific(tn_rc, rcn); 145 146 /* 147 * Let did set the RC properties excluding FRU, and label. 148 */ 149 if (did_props_set(tn_rc, did, RC_common_props, RC_propcnt - 2) < 0) { 150 topo_mod_dprintf(mod, "%s: did_props_set failed for %s = %d\n", 151 f, PCIEX_ROOT, rci); 152 topo_node_unbind(tn_rc); 153 return (-1); 154 } 155 156 if (topo_node_range_create(mod, tn_rc, PCIEX_BUS, 0, 157 MAX_HB_BUSES) != 0 && topo_mod_errno(mod) != EMOD_NODE_DUP) { 158 topo_mod_dprintf(mod, 159 "%s: create child range for %s failed: %s\n", 160 f, PCIEX_BUS, topo_mod_errmsg(mod)); 161 return (-1); 162 } 163 164 return (topo_mod_enumerate(mod, tn_rc, PCI_BUS, PCIEX_BUS, 165 0, MAX_HB_BUSES, did)); 166 } 167 168 static int 169 pci_process(topo_mod_t *mod, tnode_t *tn_hbr, di_node_t bn) 170 { 171 did_t *did; 172 tnode_t *tn_bb = topo_node_parent(tn_hbr); 173 174 if ((did = did_create(mod, bn, topo_node_instance(tn_bb), 175 topo_node_instance(tn_hbr), NO_RC, TRUST_BDF)) == NULL) 176 return (-1); 177 178 /* 179 * Let did set the hostbridge properties excluding FRU and label. 180 */ 181 (void) did_props_set(tn_hbr, did, HB_common_props, HB_propcnt - 2); 182 183 if (topo_node_range_create(mod, tn_hbr, PCI_BUS, 0, 184 MAX_HB_BUSES) != 0 && topo_mod_errno(mod) != EMOD_NODE_DUP) { 185 topo_mod_dprintf(mod, "create child range for %s failed: %s\n", 186 PCI_BUS, topo_mod_errmsg(mod)); 187 return (-1); 188 } 189 190 return (topo_mod_enumerate(mod, tn_hbr, PCI_BUS, PCI_BUS, 191 0, MAX_HB_BUSES, did)); 192 } 193 194 static int 195 x86pi_gen_pci_pciexrc(topo_mod_t *mod, tnode_t *tn_hbr, uint16_t bdf, 196 topo_instance_t *rcip) 197 { 198 di_node_t devtree, pnode, cnode; 199 200 topo_mod_dprintf(mod, "creating pci/pciexrc node bdf = %#x\n", 201 (int)bdf); 202 203 devtree = topo_mod_devinfo(mod); 204 if (devtree == DI_NODE_NIL) { 205 topo_mod_dprintf(mod, "devinfo init failed.\n"); 206 return (-1); 207 } 208 209 for (pnode = di_drv_first_node(PCI, devtree); 210 pnode != DI_NODE_NIL; pnode = di_drv_next_node(pnode)) 211 if (x86pi_bdf(mod, pnode) == bdf) 212 return (pci_process(mod, tn_hbr, pnode)); 213 214 pnode = di_drv_first_node(NPE, devtree); 215 while (pnode != DI_NODE_NIL) { 216 for (cnode = di_child_node(pnode); cnode != DI_NODE_NIL; 217 cnode = di_sibling_node(cnode)) { 218 if (di_driver_name(cnode) == NULL || 219 x86pi_bdf(mod, cnode) != bdf) 220 continue; 221 222 if (strcmp(di_driver_name(cnode), PCI_PCI) == 0) 223 return (pci_process(mod, tn_hbr, cnode)); 224 225 if (strcmp(di_driver_name(cnode), PCIEB) == 0) 226 return (pciex_process(mod, tn_hbr, 227 cnode, (*rcip)++)); 228 229 topo_mod_dprintf(mod, "no matching driver found: " 230 "bdf = %#x\n", (int)bdf); 231 } 232 pnode = di_drv_next_node(pnode); 233 } 234 235 topo_mod_dprintf(mod, "no matching bdf found: bdf = %#x\n", (int)bdf); 236 237 return (0); 238 } 239 240 int 241 x86pi_gen_hbr(topo_mod_t *mod, tnode_t *tn_bb, smbios_hdl_t *shp, 242 int hbr_smbid, topo_instance_t hbri, topo_instance_t *rcip) 243 { 244 x86pi_hcfmri_t hcfmri = {0}; 245 tnode_t *tn_hbr; 246 smbs_cnt_t *smbc = &stypes[SUN_OEM_PCIEXRC]; 247 smbios_pciexrc_t smb_rc; 248 int i, rv, err = 0; 249 const char *f = "x86pi_gen_hbr"; 250 251 hcfmri.hc_name = HOSTBRIDGE; 252 hcfmri.instance = hbri; 253 254 /* create and bind the "hostbridge" node */ 255 rv = x86pi_enum_generic(mod, &hcfmri, tn_bb, tn_bb, &tn_hbr, 0); 256 if (rv != 0) { 257 topo_mod_dprintf(mod, "%s: failed to create %s = %d\n", 258 f, HOSTBRIDGE, hbri); 259 return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM)); 260 } 261 262 /* 263 * Walk the smbios records and create the pci/pciexrc nodes 264 */ 265 for (i = 0; i < smbc->count; i++) { 266 if (smbios_info_pciexrc(shp, smbc->ids[i].id, &smb_rc) != 0) 267 topo_mod_dprintf(mod, 268 "%s: failed: id = %d\n", f, (int)smbc->ids[i].id); 269 else if (smb_rc.smbpcie_bb == hbr_smbid && 270 x86pi_gen_pci_pciexrc(mod, tn_hbr, smb_rc.smbpcie_bdf, 271 rcip) != 0) 272 err++; 273 } 274 275 return (err == 0 ? 0 : topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM)); 276 } 277