1 #include <assert.h> 2 3 #include <hei_main.hpp> 4 #include <util/pdbg.hpp> 5 #include <util/trace.hpp> 6 7 namespace util 8 { 9 10 namespace pdbg 11 { 12 13 //------------------------------------------------------------------------------ 14 15 pdbg_target* getTrgt(const libhei::Chip& i_chip) 16 { 17 return (pdbg_target*)i_chip.getChip(); 18 } 19 20 //------------------------------------------------------------------------------ 21 22 const char* getPath(pdbg_target* i_trgt) 23 { 24 return pdbg_target_path(i_trgt); 25 } 26 27 const char* getPath(const libhei::Chip& i_chip) 28 { 29 return getPath(getTrgt(i_chip)); 30 } 31 32 //------------------------------------------------------------------------------ 33 34 uint32_t getChipPos(pdbg_target* i_trgt) 35 { 36 uint32_t attr = 0; 37 pdbg_target_get_attribute(i_trgt, "ATTR_FAPI_POS", 4, 1, &attr); 38 return attr; 39 } 40 41 uint32_t getChipPos(const libhei::Chip& i_chip) 42 { 43 return getChipPos(getTrgt(i_chip)); 44 } 45 46 //------------------------------------------------------------------------------ 47 48 uint8_t getTrgtType(pdbg_target* i_trgt) 49 { 50 uint8_t attr = 0; 51 pdbg_target_get_attribute(i_trgt, "ATTR_TYPE", 1, 1, &attr); 52 return attr; 53 } 54 55 uint8_t getTrgtType(const libhei::Chip& i_chip) 56 { 57 return getTrgtType(getTrgt(i_chip)); 58 } 59 60 //------------------------------------------------------------------------------ 61 62 pdbg_target* getPibTrgt(pdbg_target* i_procTrgt) 63 { 64 // The input target must be a processor. 65 assert(TYPE_PROC == getTrgtType(i_procTrgt)); 66 67 // Get the pib path. 68 char path[16]; 69 sprintf(path, "/proc%d/pib", pdbg_target_index(i_procTrgt)); 70 71 // Return the pib target. 72 pdbg_target* pibTrgt = pdbg_target_from_path(nullptr, path); 73 assert(nullptr != pibTrgt); 74 75 return pibTrgt; 76 } 77 78 //------------------------------------------------------------------------------ 79 80 pdbg_target* getFsiTrgt(pdbg_target* i_procTrgt) 81 { 82 // The input target must be a processor. 83 assert(TYPE_PROC == getTrgtType(i_procTrgt)); 84 85 // Get the fsi path. 86 char path[16]; 87 sprintf(path, "/proc%d/fsi", pdbg_target_index(i_procTrgt)); 88 89 // Return the fsi target. 90 pdbg_target* fsiTrgt = pdbg_target_from_path(nullptr, path); 91 assert(nullptr != fsiTrgt); 92 93 return fsiTrgt; 94 } 95 96 //------------------------------------------------------------------------------ 97 98 int getCfam(pdbg_target* i_trgt, uint32_t i_addr, uint32_t& o_val) 99 { 100 // Only processor targets are supported. 101 assert(TYPE_PROC == getTrgtType(i_trgt)); 102 103 auto fsiTrgt = util::pdbg::getFsiTrgt(i_trgt); 104 105 int rc = fsi_read(fsiTrgt, i_addr, &o_val); 106 107 if (0 != rc) 108 { 109 trace::err("fsi_read failure: trgt=%s addr=0x%08x", 110 util::pdbg::getPath(fsiTrgt), i_addr); 111 } 112 113 return rc; 114 } 115 116 //------------------------------------------------------------------------------ 117 118 // IMPORTANT: 119 // The ATTR_CHIP_ID attribute will be synced from Hostboot to the BMC at some 120 // point during the IPL. It is possible that this information is needed before 121 // the sync occurs, in which case the value will return 0. 122 uint32_t __getChipId(pdbg_target* i_trgt) 123 { 124 uint32_t attr = 0; 125 pdbg_target_get_attribute(i_trgt, "ATTR_CHIP_ID", 4, 1, &attr); 126 return attr; 127 } 128 129 // IMPORTANT: 130 // The ATTR_EC attribute will be synced from Hostboot to the BMC at some point 131 // during the IPL. It is possible that this information is needed before the 132 // sync occurs, in which case the value will return 0. 133 uint8_t __getChipEc(pdbg_target* i_trgt) 134 { 135 uint8_t attr = 0; 136 pdbg_target_get_attribute(i_trgt, "ATTR_EC", 1, 1, &attr); 137 return attr; 138 } 139 140 uint32_t __getChipIdEc(pdbg_target* i_trgt) 141 { 142 auto chipId = __getChipId(i_trgt); 143 auto chipEc = __getChipEc(i_trgt); 144 145 if (((0 == chipId) || (0 == chipEc)) && (TYPE_PROC == getTrgtType(i_trgt))) 146 { 147 // There is a special case where the model/level attributes have not 148 // been initialized in the devtree. This is possible on the epoch IPL 149 // where an attention occurs before Hostboot is able to update the 150 // devtree information on the BMC. It may is still possible to get this 151 // information from chips with CFAM access (i.e. a processor) via the 152 // CFAM chip ID register. 153 154 uint32_t val = 0; 155 if (0 == getCfam(i_trgt, 0x100a, val)) 156 { 157 chipId = ((val & 0x0F0FF000) >> 12); 158 chipEc = ((val & 0xF0000000) >> 24) | ((val & 0x00F00000) >> 20); 159 } 160 } 161 162 return ((chipId & 0xffff) << 16) | (chipEc & 0xff); 163 } 164 165 void __addChip(std::vector<libhei::Chip>& o_chips, pdbg_target* i_trgt, 166 libhei::ChipType_t i_type) 167 { 168 // Trace each chip for debug. It is important to show the type just in case 169 // the model/EC does not exist. See note below. 170 trace::inf("Chip found: type=0x%08" PRIx32 " chip=%s", i_type, 171 getPath(i_trgt)); 172 173 if (0 == i_type) 174 { 175 // This is a special case. See the details in __getChipIdEC(). There is 176 // nothing more we can do with this chip since we don't know what it is. 177 // So ignore the chip for now. 178 } 179 else 180 { 181 o_chips.emplace_back(i_trgt, i_type); 182 } 183 } 184 185 void getActiveChips(std::vector<libhei::Chip>& o_chips) 186 { 187 o_chips.clear(); 188 189 // Iterate each processor. 190 pdbg_target* procTrgt; 191 pdbg_for_each_class_target("proc", procTrgt) 192 { 193 // We cannot use the proc target to determine if the chip is active. 194 // There is some design limitation in pdbg that requires the proc 195 // targets to always be active. Instead, we must get the associated pib 196 // target and check if it is active. 197 198 // Active processors only. 199 if (PDBG_TARGET_ENABLED != pdbg_target_probe(getPibTrgt(procTrgt))) 200 continue; 201 202 // Add the processor to the list. 203 __addChip(o_chips, procTrgt, __getChipIdEc(procTrgt)); 204 205 // Iterate the connected OCMBs, if they exist. 206 pdbg_target* ocmbTrgt; 207 pdbg_for_each_target("ocmb", procTrgt, ocmbTrgt) 208 { 209 // Active OCMBs only. 210 if (PDBG_TARGET_ENABLED != pdbg_target_probe(ocmbTrgt)) 211 continue; 212 213 // Add the OCMB to the list. 214 __addChip(o_chips, ocmbTrgt, __getChipIdEc(ocmbTrgt)); 215 } 216 } 217 } 218 219 //------------------------------------------------------------------------------ 220 221 bool queryHardwareAnalysisSupported() 222 { 223 // Hardware analysis is only supported on P10 systems and up. 224 return (PDBG_PROC_P9 < pdbg_get_proc()); 225 } 226 227 //------------------------------------------------------------------------------ 228 229 } // namespace pdbg 230 231 } // namespace util 232