mcamd_patounum.c (7aec1d6e) | mcamd_patounum.c (8a40a695) |
---|---|
1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the | 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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. | 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. |
8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. --- 16 unchanged lines hidden (view full) --- 32 33#include <sys/errno.h> 34#include <sys/types.h> 35#include <sys/mc.h> 36 37#include <mcamd_api.h> 38#include <mcamd_err.h> 39 | 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. --- 16 unchanged lines hidden (view full) --- 31 32#include <sys/errno.h> 33#include <sys/types.h> 34#include <sys/mc.h> 35 36#include <mcamd_api.h> 37#include <mcamd_err.h> 38 |
40extern int mc_pa_to_offset(struct mcamd_hdl *, mcamd_node_t *, mcamd_node_t *, 41 mcamd_node_t *, uint64_t, uint64_t *); | |
42 | 39 |
43#define LO_DIMM 0x1 44#define UP_DIMM 0x2 | 40#define CSDIMM1 0x1 41#define CSDIMM2 0x2 |
45 46#define BITS(val, high, low) \ 47 ((val) & (((2ULL << (high)) - 1) & ~((1ULL << (low)) - 1))) 48 | 42 43#define BITS(val, high, low) \ 44 ((val) & (((2ULL << (high)) - 1) & ~((1ULL << (low)) - 1))) 45 |
46/* 47 * iaddr_gen generates a "normalized" DRAM controller input address 48 * from a system address (physical address) if it falls within the 49 * mapped range for this memory controller. Normalisation is 50 * performed by subtracting the node base address from the system address, 51 * allowing from hoisting, and excising any bits being used in node 52 * interleaving. 53 */ |
|
49static int 50iaddr_gen(struct mcamd_hdl *hdl, mcamd_node_t *mc, uint64_t pa, 51 uint64_t *iaddrp) 52{ 53 uint64_t orig = pa; | 54static int 55iaddr_gen(struct mcamd_hdl *hdl, mcamd_node_t *mc, uint64_t pa, 56 uint64_t *iaddrp) 57{ 58 uint64_t orig = pa; |
54 uint64_t mcnum, base, lim, dramaddr, ilen, ilsel, top, dramhole; | 59 uint64_t mcnum, base, lim, dramaddr, ilen, ilsel, top, holesz; |
55 | 60 |
56 if (!mcamd_get_numprop(hdl, mc, MCAMD_PROP_NUM, &mcnum) || 57 !mcamd_get_numprop(hdl, mc, MCAMD_PROP_BASE_ADDR, &base) || 58 !mcamd_get_numprop(hdl, mc, MCAMD_PROP_LIM_ADDR, &lim) || 59 !mcamd_get_numprop(hdl, mc, MCAMD_PROP_DRAM_ILEN, &ilen) || 60 !mcamd_get_numprop(hdl, mc, MCAMD_PROP_DRAM_ILSEL, &ilsel) || 61 !mcamd_get_numprop(hdl, mc, MCAMD_PROP_DRAM_HOLE, &dramhole)) { | 61 if (!mcamd_get_numprops(hdl, 62 mc, MCAMD_PROP_NUM, &mcnum, 63 mc, MCAMD_PROP_BASE_ADDR, &base, 64 mc, MCAMD_PROP_LIM_ADDR, &lim, 65 mc, MCAMD_PROP_ILEN, &ilen, 66 mc, MCAMD_PROP_ILSEL, &ilsel, 67 mc, MCAMD_PROP_DRAMHOLE_SIZE, &holesz, 68 NULL)) { |
62 mcamd_dprintf(hdl, MCAMD_DBG_ERR, "iaddr_gen: failed to " 63 "lookup required properties"); 64 return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID)); 65 } 66 | 69 mcamd_dprintf(hdl, MCAMD_DBG_ERR, "iaddr_gen: failed to " 70 "lookup required properties"); 71 return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID)); 72 } 73 |
74 /* 75 * A node with no mapped memory (no active chip-selects is usually 76 * mapped with base and lim both zero. We'll cover that case and 77 * any other where the range is 0. 78 */ 79 if (base == lim) 80 return (mcamd_set_errno(hdl, EMCAMD_NOADDR)); 81 |
|
67 if (pa < base || pa > lim) { 68 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "iaddr_gen: PA 0x%llx not " 69 "in range [0x%llx, 0x%llx] of MC %d\n", pa, base, lim, 70 (int)mcnum); 71 return (mcamd_set_errno(hdl, EMCAMD_NOADDR)); 72 } 73 74 /* 75 * Rev E and later added the DRAM Hole Address Register for 76 * memory hoisting. In earlier revisions memory hoisting is 77 * achieved by following some algorithm to modify the CS bases etc, 78 * and this pa to unum algorithm will simply see those modified 79 * values. But if the Hole Address Register is being used then 80 * we need to reduce any address at or above 4GB by the size of 81 * the hole. 82 */ | 82 if (pa < base || pa > lim) { 83 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "iaddr_gen: PA 0x%llx not " 84 "in range [0x%llx, 0x%llx] of MC %d\n", pa, base, lim, 85 (int)mcnum); 86 return (mcamd_set_errno(hdl, EMCAMD_NOADDR)); 87 } 88 89 /* 90 * Rev E and later added the DRAM Hole Address Register for 91 * memory hoisting. In earlier revisions memory hoisting is 92 * achieved by following some algorithm to modify the CS bases etc, 93 * and this pa to unum algorithm will simply see those modified 94 * values. But if the Hole Address Register is being used then 95 * we need to reduce any address at or above 4GB by the size of 96 * the hole. 97 */ |
83 if (dramhole & MC_DC_HOLE_VALID && pa >= 0x100000000) { 84 uint64_t holesize = (dramhole & MC_DC_HOLE_OFFSET_MASK) << 85 MC_DC_HOLE_OFFSET_LSHIFT; 86 pa -= holesize; | 98 if (holesz != 0 && pa >= 0x100000000) { 99 pa -= holesz; |
87 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "iaddr_gen: dram hole " 88 "valid; pa decremented from 0x%llx to 0x%llx for " | 100 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "iaddr_gen: dram hole " 101 "valid; pa decremented from 0x%llx to 0x%llx for " |
89 "a dramhole size of 0x%llx\n", orig, pa, holesize); | 102 "a dramhole size of 0x%llx\n", orig, pa, holesz); |
90 } 91 92 dramaddr = BITS(pa, 39, 0) - BITS(base, 39, 24); 93 94 if (ilen != 0) { 95 int pailsel; 96 97 if (ilen != 1 && ilen != 3 && ilen != 7) { --- 24 unchanged lines hidden (view full) --- 122 123 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "iaddr_gen: PA 0x%llx in range " 124 "[0x%llx, 0x%llx] of MC %d; normalized address for cs compare " 125 "is 0x%llx\n", pa, base, lim, (int)mcnum, *iaddrp); 126 127 return (0); 128} 129 | 103 } 104 105 dramaddr = BITS(pa, 39, 0) - BITS(base, 39, 24); 106 107 if (ilen != 0) { 108 int pailsel; 109 110 if (ilen != 1 && ilen != 3 && ilen != 7) { --- 24 unchanged lines hidden (view full) --- 135 136 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "iaddr_gen: PA 0x%llx in range " 137 "[0x%llx, 0x%llx] of MC %d; normalized address for cs compare " 138 "is 0x%llx\n", pa, base, lim, (int)mcnum, *iaddrp); 139 140 return (0); 141} 142 |
143/* 144 * cs_match determines whether the given DRAM controller input address 145 * would be responded to by the given chip-select (which may or may not 146 * be interleaved with other chip-selects). Since we include nodes 147 * for spare chip-selects (if any) and those marked TestFail (if any) 148 * we must check chip-select-bank-enable. 149 */ |
|
130static int 131cs_match(struct mcamd_hdl *hdl, uint64_t iaddr, mcamd_node_t *cs) 132{ | 150static int 151cs_match(struct mcamd_hdl *hdl, uint64_t iaddr, mcamd_node_t *cs) 152{ |
133 uint64_t csnum, csbase, csmask; 134 int match; | 153 uint64_t csnum, csbase, csmask, csbe; 154 int match = 0; |
135 | 155 |
136 if (!mcamd_get_numprop(hdl, cs, MCAMD_PROP_NUM, &csnum) || 137 !mcamd_get_numprop(hdl, cs, MCAMD_PROP_BASE_ADDR, &csbase) || 138 !mcamd_get_numprop(hdl, cs, MCAMD_PROP_MASK, &csmask)) { | 156 if (!mcamd_get_numprops(hdl, 157 cs, MCAMD_PROP_NUM, &csnum, 158 cs, MCAMD_PROP_BASE_ADDR, &csbase, 159 cs, MCAMD_PROP_MASK, &csmask, 160 cs, MCAMD_PROP_CSBE, &csbe, 161 NULL)) { |
139 mcamd_dprintf(hdl, MCAMD_DBG_ERR, "cs_match: failed to lookup " 140 "required properties\n"); 141 return (0); 142 } 143 | 162 mcamd_dprintf(hdl, MCAMD_DBG_ERR, "cs_match: failed to lookup " 163 "required properties\n"); 164 return (0); 165 } 166 |
144 match = ((iaddr & ~csmask) == (csbase & ~csmask)); | 167 if (csbe) { 168 match = ((iaddr & ~csmask) == (csbase & ~csmask)); |
145 | 169 |
146 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "cs_match: iaddr 0x%llx does " 147 "%smatch CS %d (base 0x%llx, mask 0x%llx)\n", iaddr, 148 match ? "" : "not ", (int)csnum, csbase, csmask); | 170 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "cs_match: iaddr 0x%llx " 171 "does %smatch CS %d (base 0x%llx, mask 0x%llx)\n", iaddr, 172 match ? "" : "not ", (int)csnum, csbase, csmask); 173 } else { 174 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "cs_match: iaddr 0x%llx " 175 "does not match disabled CS %d\n", iaddr, (int)csnum); 176 } |
149 150 return (match); 151} 152 | 177 178 return (match); 179} 180 |
181/* 182 * Given a chip-select node determine whether it has been substituted 183 * by the online spare chip-select. 184 */ 185static mcamd_node_t * 186cs_sparedto(struct mcamd_hdl *hdl, mcamd_node_t *cs, mcamd_node_t *mc) 187{ 188 uint64_t csnum, badcsnum, sparecsnum, tmpcsnum; 189 190 if (!mcamd_get_numprops(hdl, 191 cs, MCAMD_PROP_NUM, &csnum, 192 mc, MCAMD_PROP_BADCS, &badcsnum, 193 mc, MCAMD_PROP_SPARECS, &sparecsnum, 194 NULL)) { 195 mcamd_dprintf(hdl, MCAMD_DBG_ERR, "cs_sparedto: failed to " 196 "lookup required properties\n"); 197 return (NULL); 198 } 199 200 if ((badcsnum == MC_INVALNUM && sparecsnum == MC_INVALNUM) || 201 csnum != badcsnum) 202 return (NULL); 203 204 for (cs = mcamd_cs_next(hdl, mc, NULL); cs != NULL; 205 cs = mcamd_cs_next(hdl, mc, cs)) { 206 if (!mcamd_get_numprop(hdl, cs, MCAMD_PROP_NUM, &tmpcsnum)) { 207 mcamd_dprintf(hdl, MCAMD_DBG_ERR, "cs_sparedto: " 208 "fail to lookup csnum - cannot reroute to spare\n"); 209 return (NULL); 210 } 211 if (tmpcsnum == sparecsnum) 212 break; 213 } 214 215 if (cs != NULL) { 216 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "cs_sparedto: cs#%d is " 217 "redirected to active online spare of cs#%d\n", csnum, 218 sparecsnum); 219 } else { 220 mcamd_dprintf(hdl, MCAMD_DBG_ERR, "cs_sparedto: cs#%d is " 221 "redirected but cannot find spare cs# - cannout reroute to " 222 "cs#%d\n", csnum, sparecsnum); 223 } 224 225 return (cs); 226} 227 228/* 229 * Having determined which node and chip-select an address maps to, 230 * as well as whether it is a dimm1, dimm2 or dimm1/dimm2 pair 231 * involved, fill the unum structure including an optional dimm offset 232 * member. 233 */ |
|
153static int 154unum_fill(struct mcamd_hdl *hdl, mcamd_node_t *cs, int which, | 234static int 235unum_fill(struct mcamd_hdl *hdl, mcamd_node_t *cs, int which, |
155 uint64_t iaddr, struct mc_unum *unump, int incloff) | 236 uint64_t iaddr, mc_unum_t *unump, int incloff) |
156{ | 237{ |
238 uint64_t chipnum, csnum, dimm1, dimm2, ranknum; |
|
157 mcamd_node_t *mc, *dimm; | 239 mcamd_node_t *mc, *dimm; |
158 uint64_t chipnum, csnum, lonum, upnum; 159 int i; | |
160 int offsetdimm; | 240 int offsetdimm; |
241 int i; |
|
161 162 if ((mc = mcamd_cs_mc(hdl, cs)) == NULL || | 242 243 if ((mc = mcamd_cs_mc(hdl, cs)) == NULL || |
163 !mcamd_get_numprop(hdl, mc, MCAMD_PROP_NUM, &chipnum) || 164 !mcamd_get_numprop(hdl, cs, MCAMD_PROP_NUM, &csnum)) { | 244 !mcamd_get_numprops(hdl, 245 mc, MCAMD_PROP_NUM, &chipnum, 246 cs, MCAMD_PROP_NUM, &csnum, 247 cs, MCAMD_PROP_DIMMRANK, &ranknum, 248 NULL)) { |
165 mcamd_dprintf(hdl, MCAMD_DBG_ERR, "unum_fill: failed to " 166 "lookup required properties\n"); 167 return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID)); 168 } 169 | 249 mcamd_dprintf(hdl, MCAMD_DBG_ERR, "unum_fill: failed to " 250 "lookup required properties\n"); 251 return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID)); 252 } 253 |
170 if ((which & LO_DIMM) && 171 !mcamd_get_numprop(hdl, cs, MCAMD_PROP_LODIMM, &lonum) || 172 (which & UP_DIMM) && 173 !mcamd_get_numprop(hdl, cs, MCAMD_PROP_UPDIMM, &upnum)) { | 254 if ((which & CSDIMM1) && 255 !mcamd_get_numprop(hdl, cs, MCAMD_PROP_CSDIMM1, &dimm1) || 256 (which & CSDIMM2) && 257 !mcamd_get_numprop(hdl, cs, MCAMD_PROP_CSDIMM2, &dimm2)) { |
174 mcamd_dprintf(hdl, MCAMD_DBG_ERR, "unum_fill: failed to " | 258 mcamd_dprintf(hdl, MCAMD_DBG_ERR, "unum_fill: failed to " |
175 "lookup lodimm/hidimm properties\n"); | 259 "lookup dimm1/dimm2 properties\n"); |
176 return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID)); 177 } 178 179 unump->unum_board = 0; 180 unump->unum_chip = chipnum; 181 unump->unum_mc = 0; 182 unump->unum_cs = csnum; | 260 return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID)); 261 } 262 263 unump->unum_board = 0; 264 unump->unum_chip = chipnum; 265 unump->unum_mc = 0; 266 unump->unum_cs = csnum; |
267 unump->unum_rank = ranknum; |
|
183 184 for (i = 0; i < MC_UNUM_NDIMM; i++) { | 268 269 for (i = 0; i < MC_UNUM_NDIMM; i++) { |
185 unump->unum_dimms[i] = -1; | 270 unump->unum_dimms[i] = MC_INVALNUM; |
186 } 187 switch (which) { | 271 } 272 switch (which) { |
188 case LO_DIMM: 189 unump->unum_dimms[0] = lonum; 190 offsetdimm = lonum; | 273 case CSDIMM1: 274 unump->unum_dimms[0] = dimm1; 275 offsetdimm = dimm1; |
191 break; | 276 break; |
192 case UP_DIMM: 193 unump->unum_dimms[0] = upnum; 194 offsetdimm = upnum; | 277 case CSDIMM2: 278 unump->unum_dimms[0] = dimm2; 279 offsetdimm = dimm2; |
195 break; | 280 break; |
196 case LO_DIMM | UP_DIMM: 197 unump->unum_dimms[0] = lonum; 198 unump->unum_dimms[1] = upnum; 199 offsetdimm = lonum; | 281 case CSDIMM1 | CSDIMM2: 282 unump->unum_dimms[0] = dimm1; 283 unump->unum_dimms[1] = dimm2; 284 offsetdimm = dimm1; |
200 break; 201 } 202 203 if (!incloff) { 204 unump->unum_offset = MCAMD_RC_INVALID_OFFSET; 205 return (0); 206 } 207 208 /* 209 * We wish to calculate a dimm offset. In the paired case we will | 285 break; 286 } 287 288 if (!incloff) { 289 unump->unum_offset = MCAMD_RC_INVALID_OFFSET; 290 return (0); 291 } 292 293 /* 294 * We wish to calculate a dimm offset. In the paired case we will |
210 * lookup the lodimm (see offsetdimm above). | 295 * lookup dimm1 (see offsetdimm above). |
211 */ 212 for (dimm = mcamd_dimm_next(hdl, mc, NULL); dimm != NULL; 213 dimm = mcamd_dimm_next(hdl, mc, dimm)) { 214 uint64_t dnum; 215 if (!mcamd_get_numprop(hdl, dimm, MCAMD_PROP_NUM, &dnum)) { 216 mcamd_dprintf(hdl, MCAMD_DBG_ERR, "unum_fill: failed " 217 "to lookup dimm number property\n"); 218 continue; --- 9 unchanged lines hidden (view full) --- 228 unump->unum_offset = MCAMD_RC_INVALID_OFFSET; 229 return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID)); 230 } 231 232 /* 233 * mc_pa_to_offset sets the offset to an invalid value if 234 * it hits an error. 235 */ | 296 */ 297 for (dimm = mcamd_dimm_next(hdl, mc, NULL); dimm != NULL; 298 dimm = mcamd_dimm_next(hdl, mc, dimm)) { 299 uint64_t dnum; 300 if (!mcamd_get_numprop(hdl, dimm, MCAMD_PROP_NUM, &dnum)) { 301 mcamd_dprintf(hdl, MCAMD_DBG_ERR, "unum_fill: failed " 302 "to lookup dimm number property\n"); 303 continue; --- 9 unchanged lines hidden (view full) --- 313 unump->unum_offset = MCAMD_RC_INVALID_OFFSET; 314 return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID)); 315 } 316 317 /* 318 * mc_pa_to_offset sets the offset to an invalid value if 319 * it hits an error. 320 */ |
236 (void) mc_pa_to_offset(hdl, mc, cs, dimm, iaddr, &unump->unum_offset); | 321 (void) mc_pa_to_offset(hdl, mc, cs, iaddr, &unump->unum_offset); |
237 238 return (0); 239} 240 241/* | 322 323 return (0); 324} 325 326/* |
242 * We have translated a system address to a (node, chip-select). That 243 * identifies one (in 64-bit MC mode) or two (in 128-bit MC mode DIMMs, 244 * either a lodimm or a lodimm/updimm pair. For all cases except an 245 * uncorrectable ChipKill error we can interpret the address alignment and 246 * syndrome to deduce whether we are on the lodimm or updimm. | 327 * We have translated a system address to a (node, chip-select), and wish 328 * to determine the associated dimm or dimms. 329 * 330 * A (node, chip-select) pair identifies one (in 64-bit MC mode) or two (in 331 * 128-bit MC mode) DIMMs. In the case of a single dimm it is usually in a 332 * lodimm (channel A) slot, but if mismatched dimm support is present it may 333 * be an updimm (channel B). 334 * 335 * Where just one dimm is associated with the chip-select we are done. 336 * Where there are two dimms associated with the chip-select we can 337 * use the ECC type and/or syndrome to determine which of the pair we 338 * resolve to, if the error is correctable. If the error is uncorrectable 339 * then in 64/8 ECC mode we can still resolve to a single dimm (since ECC 340 * is calculated and checked on each half of the data separately), but 341 * in ChipKill mode we cannot resolve down to a single dimm. |
247 */ 248static int | 342 */ 343static int |
249mc_whichdimm(struct mcamd_hdl *hdl, mcamd_node_t *mc, uint64_t pa, | 344mc_whichdimm(struct mcamd_hdl *hdl, mcamd_node_t *cs, uint64_t pa, |
250 uint32_t synd, int syndtype) 251{ | 345 uint32_t synd, int syndtype) 346{ |
252 uint64_t accwidth; 253 uint_t sym, pat; | |
254 int lobit, hibit, data, check; | 347 int lobit, hibit, data, check; |
348 uint64_t dimm1, dimm2; 349 uint_t sym, pat; 350 int ndimm; |
|
255 | 351 |
256 if (!mcamd_get_numprop(hdl, mc, MCAMD_PROP_ACCESS_WIDTH, &accwidth) || 257 (accwidth != 64 && accwidth != 128)) { 258 mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mc_whichdimm: failed " 259 "to lookup required properties\n"); | 352 /* 353 * Read the associated dimm instance numbers. The provider must 354 * assure that if there is just one dimm then it is in the first 355 * property, and if there are two then the first must be on 356 * channel A. 357 */ 358 if (!mcamd_get_numprops(hdl, 359 cs, MCAMD_PROP_CSDIMM1, &dimm1, 360 cs, MCAMD_PROP_CSDIMM2, &dimm2, 361 NULL)) { 362 mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mc_whichdimm: failed to " 363 "lookup required properties"); |
260 return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID)); 261 } | 364 return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID)); 365 } |
366 ndimm = (dimm1 != MC_INVALNUM) + (dimm2 != MC_INVALNUM); 367 if (ndimm == 0) { 368 mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mc_whichdimm: found no " 369 "dimms associated with chip-select"); 370 return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID)); 371 } |
|
262 | 372 |
263 /* 264 * In 64 bit mode only LO dimms are occupied. 265 */ 266 if (accwidth == 64) { 267 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_whichdimm: 64-bit mode " 268 "therefore LO_DIMM\n"); 269 return (LO_DIMM); | 373 if (ndimm == 1) { 374 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_whichdimm: just one " 375 "dimm associated with this chip-select"); 376 return (CSDIMM1); |
270 } 271 | 377 } 378 |
379 /* 380 * 64/8 ECC is checked separately for the upper and lower 381 * halves, so even an uncorrectable error is contained within 382 * one of the two halves. The error address is accurate to 383 * 8 bytes, so bit 4 distinguises upper from lower. 384 */ |
|
272 if (syndtype == AMD_SYNDTYPE_ECC) { | 385 if (syndtype == AMD_SYNDTYPE_ECC) { |
273 /* 274 * 64/8 ECC is checked separately for the upper and lower 275 * halves, so even an uncorrectable error is contained within 276 * one of the two halves. The error address is accurate to 277 * 8 bytes, so bit 4 distinguises upper from lower. 278 */ | |
279 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_whichdimm: 64/8 ECC " 280 "and PA 0x%llx is in %s half\n", pa, 281 pa & 8 ? "lower" : "upper"); | 386 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_whichdimm: 64/8 ECC " 387 "and PA 0x%llx is in %s half\n", pa, 388 pa & 8 ? "lower" : "upper"); |
282 return (pa & 8 ? UP_DIMM : LO_DIMM); | 389 return (pa & 8 ? CSDIMM2 : CSDIMM1); |
283 } 284 285 /* | 390 } 391 392 /* |
286 * ChipKill ECC (necessarily in 128-bit mode. | 393 * ChipKill ECC |
287 */ 288 if (mcamd_cksynd_decode(hdl, synd, &sym, &pat)) { 289 /* 290 * A correctable ChipKill syndrome and we can tell 291 * which half the error was in from the symbol number. 292 */ 293 if (mcamd_cksym_decode(hdl, sym, &lobit, &hibit, &data, 294 &check) == 0) 295 return (mcamd_set_errno(hdl, EMCAMD_SYNDINVALID)); 296 297 if (data && hibit <= 63 || check && hibit <= 7) { 298 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_whichdimm: " 299 "ChipKill symbol %d (%s %d..%d), so LODIMM\n", sym, 300 data ? "data" : "check", lobit, hibit); | 394 */ 395 if (mcamd_cksynd_decode(hdl, synd, &sym, &pat)) { 396 /* 397 * A correctable ChipKill syndrome and we can tell 398 * which half the error was in from the symbol number. 399 */ 400 if (mcamd_cksym_decode(hdl, sym, &lobit, &hibit, &data, 401 &check) == 0) 402 return (mcamd_set_errno(hdl, EMCAMD_SYNDINVALID)); 403 404 if (data && hibit <= 63 || check && hibit <= 7) { 405 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_whichdimm: " 406 "ChipKill symbol %d (%s %d..%d), so LODIMM\n", sym, 407 data ? "data" : "check", lobit, hibit); |
301 return (LO_DIMM); | 408 return (CSDIMM1); |
302 } else { 303 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_whichdimm: " 304 "ChipKill symbol %d (%s %d..%d), so UPDIMM\n", sym, 305 data ? "data" : "check", lobit, hibit); | 409 } else { 410 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_whichdimm: " 411 "ChipKill symbol %d (%s %d..%d), so UPDIMM\n", sym, 412 data ? "data" : "check", lobit, hibit); |
306 return (UP_DIMM); | 413 return (CSDIMM2); |
307 } 308 } else { 309 /* 310 * An uncorrectable error while in ChipKill ECC mode - can't 311 * tell which dimm or dimms the errors lie within. 312 */ 313 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_whichhdimm: " 314 "uncorrectable ChipKill, could be either LODIMM " 315 "or UPDIMM\n"); | 414 } 415 } else { 416 /* 417 * An uncorrectable error while in ChipKill ECC mode - can't 418 * tell which dimm or dimms the errors lie within. 419 */ 420 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_whichhdimm: " 421 "uncorrectable ChipKill, could be either LODIMM " 422 "or UPDIMM\n"); |
316 return (LO_DIMM | UP_DIMM); | 423 return (CSDIMM1 | CSDIMM2); |
317 } 318} 319 320/* | 424 } 425} 426 427/* |
321 * Brute-force BKDG pa to cs translation. The following is from BKDG 3.29 322 * so is for revisions prior to F. It is coded to look as much like the | 428 * Brute-force BKDG pa to cs translation, coded to look as much like the |
323 * BKDG code as possible. 324 */ 325static int 326mc_bkdg_patounum(struct mcamd_hdl *hdl, mcamd_node_t *mc, uint64_t pa, | 429 * BKDG code as possible. 430 */ 431static int 432mc_bkdg_patounum(struct mcamd_hdl *hdl, mcamd_node_t *mc, uint64_t pa, |
327 uint32_t synd, int syndtype, struct mc_unum *unump) | 433 uint32_t synd, int syndtype, mc_unum_t *unump) |
328{ 329 int which; | 434{ 435 int which; |
330 uint64_t mcnum; | 436 uint64_t mcnum, rev; |
331 mcamd_node_t *cs; 332 /* | 437 mcamd_node_t *cs; 438 /* |
439 * Raw registers as per BKDG 440 */ 441 uint32_t HoleEn; 442 uint32_t DramBase, DramLimit; 443 uint32_t CSBase, CSMask; 444 /* |
|
333 * Variables as per BKDG 334 */ 335 int Ilog; 336 uint32_t SystemAddr = (uint32_t)(pa >> 8); 337 uint64_t IntlvEn, IntlvSel; | 445 * Variables as per BKDG 446 */ 447 int Ilog; 448 uint32_t SystemAddr = (uint32_t)(pa >> 8); 449 uint64_t IntlvEn, IntlvSel; |
338 uint32_t DramBase, DramLimit; /* assume DramEn */ 339 uint32_t HoleOffset, HoleEn; 340 uint32_t CSBase, CSMask; /* assuume CSBE */ | 450 uint32_t HoleOffset; |
341 uint32_t InputAddr, Temp; 342 | 451 uint32_t InputAddr, Temp; 452 |
343 /* 344 * Additional variables which we need since we will reading 345 * MC properties instead of PCI config space, and the MC properties 346 * are stored in a cooked state. 347 */ 348 uint64_t prop_drambase, prop_dramlimit, prop_dramhole; 349 uint64_t prop_intlven, prop_intlvsel; 350 uint64_t prop_csbase, prop_csmask; 351 352 if (!mcamd_get_numprop(hdl, mc, MCAMD_PROP_NUM, &mcnum) || 353 !mcamd_get_numprop(hdl, mc, MCAMD_PROP_BASE_ADDR, &prop_drambase) || 354 !mcamd_get_numprop(hdl, mc, MCAMD_PROP_LIM_ADDR, &prop_dramlimit) || 355 !mcamd_get_numprop(hdl, mc, MCAMD_PROP_DRAM_HOLE, &prop_dramhole) || 356 !mcamd_get_numprop(hdl, mc, MCAMD_PROP_DRAM_ILEN, &prop_intlven) || 357 !mcamd_get_numprop(hdl, mc, MCAMD_PROP_DRAM_ILSEL, 358 &prop_intlvsel)) { | 453 if (!mcamd_get_numprops(hdl, 454 mc, MCAMD_PROP_NUM, &mcnum, 455 mc, MCAMD_PROP_REV, &rev, NULL) || !mcamd_get_cfgregs(hdl, 456 mc, MCAMD_REG_DRAMBASE, &DramBase, 457 mc, MCAMD_REG_DRAMLIMIT, &DramLimit, 458 mc, MCAMD_REG_DRAMHOLE, &HoleEn, NULL)) { |
359 mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mc_bkdg_patounm: failed " | 459 mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mc_bkdg_patounm: failed " |
360 "to lookup required properties\n"); | 460 "to lookup required properties and registers\n"); |
361 return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID)); 362 } 363 364 /* | 461 return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID)); 462 } 463 464 /* |
365 * Brute force deconstruction of the MC properties. If we decide to 366 * keep this then we need some of the mcamd.g defines available to us. | 465 * BKDG line to skip Why 466 * 467 * F1Offset = ... Register already read, 468 * DramBase = Get_PCI() and retrieved above. 469 * DramEn = ... Function only called for enabled nodes. |
367 */ | 470 */ |
368 DramBase = ((prop_drambase >> 8) & 0xffff0000) | (prop_intlven << 8); | |
369 IntlvEn = (DramBase & 0x00000700) >> 8; 370 DramBase &= 0xffff0000; | 471 IntlvEn = (DramBase & 0x00000700) >> 8; 472 DramBase &= 0xffff0000; |
371 DramLimit = ((prop_dramlimit >> 8) & 0xffff0000) | (prop_intlvsel << 8); | 473 /* DramLimit = Get_PCI() Retrieved above */ |
372 IntlvSel = (DramLimit & 0x00000700) >> 8; 373 DramLimit |= 0x0000ffff; | 474 IntlvSel = (DramLimit & 0x00000700) >> 8; 475 DramLimit |= 0x0000ffff; |
374 HoleEn = prop_dramhole; /* uncooked */ | 476 /* HoleEn = ... Retrieved above */ |
375 HoleOffset = (HoleEn & 0x0000ff00) << 8; 376 HoleEn &= 0x00000001; 377 378 if (!(DramBase <= SystemAddr && SystemAddr <= DramLimit)) { 379 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_bkdg_patounum: " 380 "SystemAddr 0x%x derived from PA 0x%llx is not in the " 381 "address range [0x%x, 0x%x] of MC %d\n", 382 SystemAddr, pa, DramBase, DramLimit, (int)mcnum); 383 return (mcamd_set_errno(hdl, EMCAMD_NOADDR)); 384 } 385 | 477 HoleOffset = (HoleEn & 0x0000ff00) << 8; 478 HoleEn &= 0x00000001; 479 480 if (!(DramBase <= SystemAddr && SystemAddr <= DramLimit)) { 481 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_bkdg_patounum: " 482 "SystemAddr 0x%x derived from PA 0x%llx is not in the " 483 "address range [0x%x, 0x%x] of MC %d\n", 484 SystemAddr, pa, DramBase, DramLimit, (int)mcnum); 485 return (mcamd_set_errno(hdl, EMCAMD_NOADDR)); 486 } 487 |
488 if (HoleEn && SystemAddr > 0x00ffffff) 489 InputAddr = SystemAddr - HoleOffset; 490 491 InputAddr = SystemAddr - DramBase; 492 |
|
386 if (IntlvEn) { 387 if (IntlvSel == ((SystemAddr >> 4) & IntlvEn)) { 388 switch (IntlvEn) { 389 case 1: 390 Ilog = 1; 391 break; 392 case 3: 393 Ilog = 2; 394 break; 395 case 7: 396 Ilog = 3; 397 break; 398 default: 399 return (mcamd_set_errno(hdl, 400 EMCAMD_TREEINVALID)); 401 } | 493 if (IntlvEn) { 494 if (IntlvSel == ((SystemAddr >> 4) & IntlvEn)) { 495 switch (IntlvEn) { 496 case 1: 497 Ilog = 1; 498 break; 499 case 3: 500 Ilog = 2; 501 break; 502 case 7: 503 Ilog = 3; 504 break; 505 default: 506 return (mcamd_set_errno(hdl, 507 EMCAMD_TREEINVALID)); 508 } |
402 Temp = (SystemAddr >> (4 + Ilog)) << 4; 403 InputAddr = (Temp | (SystemAddr & 0x0000000f)) << 4; | 509 Temp = (InputAddr >> (4 + Ilog)) << 4; 510 InputAddr = (Temp | (SystemAddr & 0x0000000f)); |
404 } else { 405 /* not this node */ 406 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_bkdg_patounum: " 407 "Node interleaving, MC node %d not selected\n", 408 (int)mcnum); 409 return (mcamd_set_errno(hdl, EMCAMD_NOADDR)); 410 } | 511 } else { 512 /* not this node */ 513 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_bkdg_patounum: " 514 "Node interleaving, MC node %d not selected\n", 515 (int)mcnum); 516 return (mcamd_set_errno(hdl, EMCAMD_NOADDR)); 517 } |
411 } else { 412 /* No interleave */ 413 InputAddr = (SystemAddr - DramBase) << 4; | |
414 } 415 | 518 } 519 |
416 if (HoleEn && SystemAddr > 0x00ffffff) 417 InputAddr -= HoleOffset; | 520 if (!MC_REV_MATCH(rev, MC_REVS_FG)) 521 InputAddr <<= 4; |
418 419 for (cs = mcamd_cs_next(hdl, mc, NULL); cs != NULL; 420 cs = mcamd_cs_next(hdl, mc, cs)) { | 522 523 for (cs = mcamd_cs_next(hdl, mc, NULL); cs != NULL; 524 cs = mcamd_cs_next(hdl, mc, cs)) { |
421 uint64_t csnum; | 525 uint64_t csnum, CSEn; |
422 | 526 |
423 if (!mcamd_get_numprop(hdl, cs, MCAMD_PROP_BASE_ADDR, 424 &prop_csbase) || 425 !mcamd_get_numprop(hdl, cs, MCAMD_PROP_MASK, 426 &prop_csmask) || 427 !mcamd_get_numprop(hdl, cs, MCAMD_PROP_NUM, &csnum)) { | 527 if (!mcamd_get_cfgregs(hdl, 528 cs, MCAMD_REG_CSBASE, &CSBase, 529 cs, MCAMD_REG_CSMASK, &CSMask, 530 NULL) || 531 !mcamd_get_numprops(hdl, 532 cs, MCAMD_PROP_NUM, &csnum, 533 cs, MCAMD_PROP_CSBE, &CSEn, 534 NULL)) { |
428 mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mc_bkdg_patounm: " | 535 mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mc_bkdg_patounm: " |
429 "failed to read cs properties\n"); | 536 "failed to read cs registers\n"); |
430 return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID)); 431 } 432 | 537 return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID)); 538 } 539 |
433 CSBase = ((prop_csbase >> 4) & 0xffe00000) | 434 ((prop_csbase >> 4) & 0x0000fe00); 435 CSBase &= 0xffe0fe00; 436 CSMask = ((prop_csmask >> 4) & 0x3fe00000) | 437 ((prop_csmask >> 4) & 0x0000fe00); 438 CSMask = (CSMask | 0x001f01ff) & 0x3fffffff; | 540 /* 541 * BKDG line to skip Why 542 * 543 * F2Offset = Register already read, 544 * F2MaskOffset (rev F) Register already read 545 * CSBase = Register already read 546 * CSEn = We only keep enabled cs. 547 */ 548 if (MC_REV_MATCH(rev, MC_REVS_FG)) { 549 CSBase &= 0x1ff83fe0; 550 /* CSMask = Get_PCI() Retrieved above */ 551 CSMask = (CSMask | 0x0007c01f) & 0x1fffffff; 552 } else { 553 CSBase &= 0xffe0fe00; 554 /* CSMask = Get_PCI() Retrieved above */ 555 CSMask = (CSMask | 0x001f01ff) & 0x3fffffff; 556 } |
439 | 557 |
440 if (((InputAddr & ~CSMask) == (CSBase & ~CSMask))) { | 558 if (CSEn && (InputAddr & ~CSMask) == (CSBase & ~CSMask)) { 559 mcamd_node_t *sparecs; 560 |
441 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_bkdg_patounum: " 442 "match for chip select %d of MC %d\n", (int)csnum, 443 (int)mcnum); 444 | 561 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_bkdg_patounum: " 562 "match for chip select %d of MC %d\n", (int)csnum, 563 (int)mcnum); 564 |
445 if ((which = mc_whichdimm(hdl, mc, pa, synd, | 565 if ((sparecs = cs_sparedto(hdl, cs, mc)) != NULL) 566 cs = sparecs; 567 568 if ((which = mc_whichdimm(hdl, cs, pa, synd, |
446 syndtype)) < 0) 447 return (-1); /* errno is set for us */ 448 449 /* 450 * The BKDG algorithm drops low-order bits that 451 * are unimportant in deriving chip-select but are 452 * included in row/col/bank mapping, so do not 453 * perform offset calculation in this case. --- 6 unchanged lines hidden (view full) --- 460 } 461 462 mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mc_bkdg_patounum: in range " 463 "for MC %d but no cs responds\n", (int)mcnum); 464 465 return (mcamd_set_errno(hdl, EMCAMD_NOADDR)); 466} 467 | 569 syndtype)) < 0) 570 return (-1); /* errno is set for us */ 571 572 /* 573 * The BKDG algorithm drops low-order bits that 574 * are unimportant in deriving chip-select but are 575 * included in row/col/bank mapping, so do not 576 * perform offset calculation in this case. --- 6 unchanged lines hidden (view full) --- 583 } 584 585 mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mc_bkdg_patounum: in range " 586 "for MC %d but no cs responds\n", (int)mcnum); 587 588 return (mcamd_set_errno(hdl, EMCAMD_NOADDR)); 589} 590 |
591/* 592 * Called for each memory controller to see if the given address is 593 * mapped to this node (as determined in iaddr_gen) and, if so, which 594 * chip-select on this node responds. 595 */ 596 |
|
468/*ARGSUSED*/ 469static int 470mc_patounum(struct mcamd_hdl *hdl, mcamd_node_t *mc, uint64_t pa, | 597/*ARGSUSED*/ 598static int 599mc_patounum(struct mcamd_hdl *hdl, mcamd_node_t *mc, uint64_t pa, |
471 uint32_t synd, int syndtype, struct mc_unum *unump) | 600 uint32_t synd, int syndtype, mc_unum_t *unump) |
472{ 473 uint64_t iaddr; | 601{ 602 uint64_t iaddr; |
474 mcamd_node_t *cs; | 603 mcamd_node_t *cs, *sparecs; |
475 int which; 476#ifdef DEBUG | 604 int which; 605#ifdef DEBUG |
477 struct mc_unum bkdg_unum; | 606 mc_unum_t bkdg_unum; |
478 int bkdgres; 479 480 /* 481 * We perform the translation twice, once using the brute-force 482 * approach of the BKDG and again using a more elegant but more | 607 int bkdgres; 608 609 /* 610 * We perform the translation twice, once using the brute-force 611 * approach of the BKDG and again using a more elegant but more |
483 * difficult to review against the BKDG approach. Note that both 484 * approaches need to change for rev F since it increases max CS 485 * size and so iaddr calculation etc changes. | 612 * difficult to review against the BKDG approach. |
486 */ 487 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "BKDG brute-force method begins\n"); 488 bkdgres = mc_bkdg_patounum(hdl, mc, pa, synd, syndtype, &bkdg_unum); 489 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "BKDG brute-force method ends\n"); 490#endif 491 492 if (iaddr_gen(hdl, mc, pa, &iaddr) < 0) 493 return (-1); /* errno is set for us */ 494 495 for (cs = mcamd_cs_next(hdl, mc, NULL); cs != NULL; 496 cs = mcamd_cs_next(hdl, mc, cs)) { 497 if (cs_match(hdl, iaddr, cs)) 498 break; 499 } 500 501 if (cs == NULL) 502 return (mcamd_set_errno(hdl, EMCAMD_NOADDR)); 503 | 613 */ 614 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "BKDG brute-force method begins\n"); 615 bkdgres = mc_bkdg_patounum(hdl, mc, pa, synd, syndtype, &bkdg_unum); 616 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "BKDG brute-force method ends\n"); 617#endif 618 619 if (iaddr_gen(hdl, mc, pa, &iaddr) < 0) 620 return (-1); /* errno is set for us */ 621 622 for (cs = mcamd_cs_next(hdl, mc, NULL); cs != NULL; 623 cs = mcamd_cs_next(hdl, mc, cs)) { 624 if (cs_match(hdl, iaddr, cs)) 625 break; 626 } 627 628 if (cs == NULL) 629 return (mcamd_set_errno(hdl, EMCAMD_NOADDR)); 630 |
504 if ((which = mc_whichdimm(hdl, mc, pa, synd, syndtype)) < 0) | 631 /* 632 * If the spare chip-select has been swapped in for the one just 633 * matched then it is really the spare that we are after. Note that 634 * when the swap is done the csbase, csmask and CSBE of the spare 635 * rank do not change - accesses to the bad rank (as nominated in 636 * the Online Spare Control Register) are redirect to the spare. 637 */ 638 if ((sparecs = cs_sparedto(hdl, cs, mc)) != NULL) { 639 cs = sparecs; 640 } 641 642 if ((which = mc_whichdimm(hdl, cs, pa, synd, syndtype)) < 0) |
505 return (-1); /* errno is set for us */ 506 507 if (unum_fill(hdl, cs, which, iaddr, unump, 1) < 0) 508 return (-1); /* errno is set for us */ 509 510#ifdef DEBUG 511 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "bkdgres=%d res=0\n", bkdgres); | 643 return (-1); /* errno is set for us */ 644 645 if (unum_fill(hdl, cs, which, iaddr, unump, 1) < 0) 646 return (-1); /* errno is set for us */ 647 648#ifdef DEBUG 649 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "bkdgres=%d res=0\n", bkdgres); |
512#ifndef _KERNEL | |
513 /* offset is not checked - see note in BKDG algorithm */ | 650 /* offset is not checked - see note in BKDG algorithm */ |
514 assert(bkdgres == 0 && unump->unum_board == bkdg_unum.unum_board && | 651 if (bkdgres != 0) { 652 mcamd_dprintf(hdl, MCAMD_DBG_ERR, "BKDG alg failed while " 653 "ours succeeded\n"); 654 } else if (!(unump->unum_board == bkdg_unum.unum_board && |
515 unump->unum_chip == bkdg_unum.unum_chip && 516 unump->unum_mc == bkdg_unum.unum_mc && 517 unump->unum_cs == bkdg_unum.unum_cs && 518 unump->unum_dimms[0] == bkdg_unum.unum_dimms[0] && | 655 unump->unum_chip == bkdg_unum.unum_chip && 656 unump->unum_mc == bkdg_unum.unum_mc && 657 unump->unum_cs == bkdg_unum.unum_cs && 658 unump->unum_dimms[0] == bkdg_unum.unum_dimms[0] && |
519 unump->unum_dimms[1] == bkdg_unum.unum_dimms[1]); 520#endif /* !_KERNEL */ | 659 unump->unum_dimms[1] == bkdg_unum.unum_dimms[1])) { 660 mcamd_dprintf(hdl, MCAMD_DBG_ERR, 661 "BKDG: node %d mc %d cs %d dimm(s) %d/%d\n" 662 "Ours: node 5d mc %d cs %d dimm(s) %d/%d\n", 663 bkdg_unum.unum_chip, bkdg_unum.unum_mc, bkdg_unum.unum_cs, 664 bkdg_unum.unum_dimms[0], bkdg_unum.unum_dimms[1], 665 unump->unum_chip, unump->unum_mc, unump->unum_cs, 666 unump->unum_dimms[0], unump->unum_dimms[1]); 667 } |
521#endif /* DEBUG */ 522 523 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "Result: chip %d mc %d cs %d " 524 "offset 0x%llx\n", unump->unum_chip, unump->unum_mc, 525 unump->unum_cs, unump->unum_offset); 526 527 return (0); 528} 529 530int 531mcamd_patounum(struct mcamd_hdl *hdl, mcamd_node_t *root, uint64_t pa, | 668#endif /* DEBUG */ 669 670 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "Result: chip %d mc %d cs %d " 671 "offset 0x%llx\n", unump->unum_chip, unump->unum_mc, 672 unump->unum_cs, unump->unum_offset); 673 674 return (0); 675} 676 677int 678mcamd_patounum(struct mcamd_hdl *hdl, mcamd_node_t *root, uint64_t pa, |
532 uint32_t synd, int syndtype, struct mc_unum *unump) | 679 uint32_t synd, int syndtype, mc_unum_t *unump) |
533{ 534 mcamd_node_t *mc; 535 536 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_patounum: pa=0x%llx, " 537 "synd=0x%x, syndtype=%d\n", pa, synd, syndtype); 538 | 680{ 681 mcamd_node_t *mc; 682 683 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_patounum: pa=0x%llx, " 684 "synd=0x%x, syndtype=%d\n", pa, synd, syndtype); 685 |
686 /* 687 * Consider allowing syndrome 0 to act as a generic multibit 688 * syndrome. For example icache inf_sys_ecc1 captures an address 689 * but no syndrome - we can still resolve this to a dimm or dimms. 690 */ |
|
539 if (!mcamd_synd_validate(hdl, synd, syndtype)) 540 return (mcamd_set_errno(hdl, EMCAMD_SYNDINVALID)); 541 542 for (mc = mcamd_mc_next(hdl, root, NULL); mc != NULL; 543 mc = mcamd_mc_next(hdl, root, mc)) { 544 if (mc_patounum(hdl, mc, pa, synd, syndtype, unump) == 0) 545 return (0); 546 547 if (mcamd_errno(hdl) != EMCAMD_NOADDR) 548 break; 549 } 550 551 return (-1); /* errno is set for us */ 552} | 691 if (!mcamd_synd_validate(hdl, synd, syndtype)) 692 return (mcamd_set_errno(hdl, EMCAMD_SYNDINVALID)); 693 694 for (mc = mcamd_mc_next(hdl, root, NULL); mc != NULL; 695 mc = mcamd_mc_next(hdl, root, mc)) { 696 if (mc_patounum(hdl, mc, pa, synd, syndtype, unump) == 0) 697 return (0); 698 699 if (mcamd_errno(hdl) != EMCAMD_NOADDR) 700 break; 701 } 702 703 return (-1); /* errno is set for us */ 704} |