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 2009 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 uint16_t 103 x86pi_bdf(topo_mod_t *mod, di_node_t node) 104 { 105 int *val; 106 107 if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "reg", &val) < 0) { 108 topo_mod_dprintf(mod, "couldn't get \"reg\" prop: %s.\n", 109 strerror(errno)); 110 return ((uint16_t)-1); 111 } 112 113 return (uint16_t)((*val & PCI_REG_BDFR_M) >> PCI_REG_FUNC_SHIFT); 114 } 115 116 static int 117 pciex_process(topo_mod_t *mod, tnode_t *tn_hbr, di_node_t rcn, 118 topo_instance_t rci) 119 { 120 did_t *did; 121 int rv; 122 tnode_t *tn_rc; 123 x86pi_hcfmri_t hcfmri = {0}; 124 tnode_t *tn_bb = topo_node_parent(tn_hbr); 125 const char *f = "pciexrc_process"; 126 127 if ((did = did_create(mod, rcn, topo_node_instance(tn_bb), 128 topo_node_instance(tn_hbr), rci, TRUST_BDF)) == NULL) 129 return (NULL); 130 131 did_markrc(did); 132 133 /* 134 * Let did set the hostbridge properties excluding FRU and label. 135 */ 136 (void) did_props_set(tn_hbr, did, ExHB_common_props, ExHB_propcnt - 2); 137 138 if (topo_node_range_create(mod, tn_hbr, PCIEX_ROOT, 0, 139 MAX_HB_BUSES) != 0 && topo_mod_errno(mod) != EMOD_NODE_DUP) { 140 topo_mod_dprintf(mod, 141 "%s: create child range for %s failed: %s\n", 142 f, PCIEX_ROOT, topo_mod_errmsg(mod)); 143 return (-1); 144 } 145 146 hcfmri.hc_name = PCIEX_ROOT; 147 hcfmri.instance = rci; 148 rv = x86pi_enum_generic(mod, &hcfmri, tn_hbr, tn_hbr, &tn_rc, 0); 149 if (rv != 0) { 150 topo_mod_dprintf(mod, "%s: failed to create %s = %d\n", 151 f, PCIEX_ROOT, rci); 152 return (-1); 153 } 154 155 /* 156 * pcibus enumerator requires di_node_t be set in node specific 157 */ 158 topo_node_setspecific(tn_rc, rcn); 159 160 /* 161 * Let did set the RC properties excluding FRU, and label. 162 */ 163 if (did_props_set(tn_rc, did, RC_common_props, RC_propcnt - 2) < 0) { 164 topo_mod_dprintf(mod, "%s: did_props_set failed for %s = %d\n", 165 f, PCIEX_ROOT, rci); 166 topo_node_unbind(tn_rc); 167 return (-1); 168 } 169 170 if (topo_node_range_create(mod, tn_rc, PCIEX_BUS, 0, 171 MAX_HB_BUSES) != 0 && topo_mod_errno(mod) != EMOD_NODE_DUP) { 172 topo_mod_dprintf(mod, 173 "%s: create child range for %s failed: %s\n", 174 f, PCIEX_BUS, topo_mod_errmsg(mod)); 175 return (-1); 176 } 177 178 return (topo_mod_enumerate(mod, tn_rc, PCI_BUS, PCIEX_BUS, 179 0, MAX_HB_BUSES, did)); 180 } 181 182 static int 183 pci_process(topo_mod_t *mod, tnode_t *tn_hbr, di_node_t bn) 184 { 185 did_t *did; 186 tnode_t *tn_bb = topo_node_parent(tn_hbr); 187 188 if ((did = did_create(mod, bn, topo_node_instance(tn_bb), 189 topo_node_instance(tn_hbr), NO_RC, TRUST_BDF)) == NULL) 190 return (-1); 191 192 /* 193 * Let did set the hostbridge properties excluding FRU and label. 194 */ 195 (void) did_props_set(tn_hbr, did, HB_common_props, HB_propcnt - 2); 196 197 if (topo_node_range_create(mod, tn_hbr, PCI_BUS, 0, 198 MAX_HB_BUSES) != 0 && topo_mod_errno(mod) != EMOD_NODE_DUP) { 199 topo_mod_dprintf(mod, "create child range for %s failed: %s\n", 200 PCI_BUS, topo_mod_errmsg(mod)); 201 return (-1); 202 } 203 204 return (topo_mod_enumerate(mod, tn_hbr, PCI_BUS, PCI_BUS, 205 0, MAX_HB_BUSES, did)); 206 } 207 208 static int 209 x86pi_gen_pci_pciexrc(topo_mod_t *mod, tnode_t *tn_hbr, uint16_t bdf, 210 topo_instance_t *rcip) 211 { 212 di_node_t devtree, pnode, cnode; 213 214 topo_mod_dprintf(mod, "creating pci/pciexrc node bdf = %#x\n", 215 (int)bdf); 216 217 devtree = topo_mod_devinfo(mod); 218 if (devtree == DI_NODE_NIL) { 219 topo_mod_dprintf(mod, "devinfo init failed.\n"); 220 return (-1); 221 } 222 223 for (pnode = di_drv_first_node(PCI, devtree); 224 pnode != DI_NODE_NIL; pnode = di_drv_next_node(pnode)) 225 if (x86pi_bdf(mod, pnode) == bdf) 226 return (pci_process(mod, tn_hbr, pnode)); 227 228 pnode = di_drv_first_node(NPE, devtree); 229 while (pnode != DI_NODE_NIL) { 230 for (cnode = di_child_node(pnode); cnode != DI_NODE_NIL; 231 cnode = di_sibling_node(cnode)) { 232 if (di_driver_name(cnode) == NULL || 233 x86pi_bdf(mod, cnode) != bdf) 234 continue; 235 236 if (strcmp(di_driver_name(cnode), PCI_PCI) == 0) 237 return (pci_process(mod, tn_hbr, cnode)); 238 239 if (strcmp(di_driver_name(cnode), PCIEB) == 0) 240 return (pciex_process(mod, tn_hbr, 241 cnode, (*rcip)++)); 242 243 topo_mod_dprintf(mod, "no matching driver found: " 244 "bdf = %#x\n", (int)bdf); 245 } 246 pnode = di_drv_next_node(pnode); 247 } 248 249 topo_mod_dprintf(mod, "no matching bdf found: bdf = %#x\n", (int)bdf); 250 251 return (0); 252 } 253 254 int 255 x86pi_gen_hbr(topo_mod_t *mod, tnode_t *tn_bb, smbios_hdl_t *shp, 256 int hbr_smbid, topo_instance_t hbri, topo_instance_t *rcip) 257 { 258 x86pi_hcfmri_t hcfmri = {0}; 259 tnode_t *tn_hbr; 260 smbs_cnt_t *smbc = &stypes[SUN_OEM_PCIEXRC]; 261 smbios_pciexrc_t smb_rc; 262 int i, rv, err = 0; 263 const char *f = "x86pi_gen_hbr"; 264 265 hcfmri.hc_name = HOSTBRIDGE; 266 hcfmri.instance = hbri; 267 268 /* create and bind the "hostbridge" node */ 269 rv = x86pi_enum_generic(mod, &hcfmri, tn_bb, tn_bb, &tn_hbr, 0); 270 if (rv != 0) { 271 topo_mod_dprintf(mod, "%s: failed to create %s = %d\n", 272 f, HOSTBRIDGE, hbri); 273 return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM)); 274 } 275 276 /* 277 * Walk the smbios records and create the pci/pciexrc nodes 278 */ 279 for (i = 0; i < smbc->count; i++) { 280 if (smbios_info_pciexrc(shp, smbc->ids[i].id, &smb_rc) != 0) 281 topo_mod_dprintf(mod, 282 "%s: failed: id = %d\n", f, (int)smbc->ids[i].id); 283 else if (smb_rc.smbpcie_bb == hbr_smbid && 284 x86pi_gen_pci_pciexrc(mod, tn_hbr, smb_rc.smbpcie_bdf, 285 rcip) != 0) 286 err++; 287 } 288 289 return (err == 0 ? 0 : topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM)); 290 } 291