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