mcamd_patounum.c (8a40a695) | mcamd_patounum.c (4156fc34) |
---|---|
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 --- 22 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 | 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 --- 22 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 |
39#define MC_SYSADDR_MSB 39 40#define MC_SYSADDR_LSB 3 |
|
39 40#define CSDIMM1 0x1 41#define CSDIMM2 0x2 42 43#define BITS(val, high, low) \ 44 ((val) & (((2ULL << (high)) - 1) & ~((1ULL << (low)) - 1))) 45 46/* --- 290 unchanged lines hidden (view full) --- 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. 342 */ 343static int 344mc_whichdimm(struct mcamd_hdl *hdl, mcamd_node_t *cs, uint64_t pa, | 41 42#define CSDIMM1 0x1 43#define CSDIMM2 0x2 44 45#define BITS(val, high, low) \ 46 ((val) & (((2ULL << (high)) - 1) & ~((1ULL << (low)) - 1))) 47 48/* --- 290 unchanged lines hidden (view full) --- 339 * use the ECC type and/or syndrome to determine which of the pair we 340 * resolve to, if the error is correctable. If the error is uncorrectable 341 * then in 64/8 ECC mode we can still resolve to a single dimm (since ECC 342 * is calculated and checked on each half of the data separately), but 343 * in ChipKill mode we cannot resolve down to a single dimm. 344 */ 345static int 346mc_whichdimm(struct mcamd_hdl *hdl, mcamd_node_t *cs, uint64_t pa, |
345 uint32_t synd, int syndtype) | 347 uint8_t valid_lo, uint32_t synd, int syndtype) |
346{ 347 int lobit, hibit, data, check; 348 uint64_t dimm1, dimm2; 349 uint_t sym, pat; 350 int ndimm; 351 352 /* 353 * Read the associated dimm instance numbers. The provider must --- 20 unchanged lines hidden (view full) --- 374 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_whichdimm: just one " 375 "dimm associated with this chip-select"); 376 return (CSDIMM1); 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 | 348{ 349 int lobit, hibit, data, check; 350 uint64_t dimm1, dimm2; 351 uint_t sym, pat; 352 int ndimm; 353 354 /* 355 * Read the associated dimm instance numbers. The provider must --- 20 unchanged lines hidden (view full) --- 376 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_whichdimm: just one " 377 "dimm associated with this chip-select"); 378 return (CSDIMM1); 379 } 380 381 /* 382 * 64/8 ECC is checked separately for the upper and lower 383 * 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 * one of the two halves. If we have sufficient address resolution 385 * then we can determine which DIMM. |
384 */ 385 if (syndtype == AMD_SYNDTYPE_ECC) { | 386 */ 387 if (syndtype == AMD_SYNDTYPE_ECC) { |
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"); 389 return (pa & 8 ? CSDIMM2 : CSDIMM1); | 388 if (valid_lo <= MC_SYSADDR_LSB) { 389 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_whichdimm: 64/8 " 390 "ECC in 128-bit mode, PA 0x%llx is in %s half\n", 391 pa, pa & 0x8 ? "upper" : "lower"); 392 return (pa & 0x8 ? CSDIMM2 : CSDIMM1); 393 } else { 394 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_whichdimm: " 395 "64/8 ECC in 128-bit mode, PA 0x%llx with least " 396 "significant valid bit %d cannot be resolved to " 397 "a single DIMM\n", pa, valid_lo); 398 return (mcamd_set_errno(hdl, EMCAMD_INSUFF_RES)); 399 } |
390 } 391 392 /* 393 * ChipKill ECC 394 */ 395 if (mcamd_cksynd_decode(hdl, synd, &sym, &pat)) { 396 /* 397 * A correctable ChipKill syndrome and we can tell --- 27 unchanged lines hidden (view full) --- 425} 426 427/* 428 * Brute-force BKDG pa to cs translation, coded to look as much like the 429 * BKDG code as possible. 430 */ 431static int 432mc_bkdg_patounum(struct mcamd_hdl *hdl, mcamd_node_t *mc, uint64_t pa, | 400 } 401 402 /* 403 * ChipKill ECC 404 */ 405 if (mcamd_cksynd_decode(hdl, synd, &sym, &pat)) { 406 /* 407 * A correctable ChipKill syndrome and we can tell --- 27 unchanged lines hidden (view full) --- 435} 436 437/* 438 * Brute-force BKDG pa to cs translation, coded to look as much like the 439 * BKDG code as possible. 440 */ 441static int 442mc_bkdg_patounum(struct mcamd_hdl *hdl, mcamd_node_t *mc, uint64_t pa, |
433 uint32_t synd, int syndtype, mc_unum_t *unump) | 443 uint8_t valid_lo, uint32_t synd, int syndtype, 444 mc_unum_t *unump) |
434{ 435 int which; 436 uint64_t mcnum, rev; 437 mcamd_node_t *cs; 438 /* 439 * Raw registers as per BKDG 440 */ 441 uint32_t HoleEn; --- 118 unchanged lines hidden (view full) --- 560 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 565 if ((sparecs = cs_sparedto(hdl, cs, mc)) != NULL) 566 cs = sparecs; 567 | 445{ 446 int which; 447 uint64_t mcnum, rev; 448 mcamd_node_t *cs; 449 /* 450 * Raw registers as per BKDG 451 */ 452 uint32_t HoleEn; --- 118 unchanged lines hidden (view full) --- 571 572 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_bkdg_patounum: " 573 "match for chip select %d of MC %d\n", (int)csnum, 574 (int)mcnum); 575 576 if ((sparecs = cs_sparedto(hdl, cs, mc)) != NULL) 577 cs = sparecs; 578 |
568 if ((which = mc_whichdimm(hdl, cs, pa, synd, 569 syndtype)) < 0) | 579 if ((which = mc_whichdimm(hdl, cs, pa, valid_lo, 580 synd, 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. 577 */ --- 14 unchanged lines hidden (view full) --- 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 597/*ARGSUSED*/ 598static int 599mc_patounum(struct mcamd_hdl *hdl, mcamd_node_t *mc, uint64_t pa, | 581 return (-1); /* errno is set for us */ 582 583 /* 584 * The BKDG algorithm drops low-order bits that 585 * are unimportant in deriving chip-select but are 586 * included in row/col/bank mapping, so do not 587 * perform offset calculation in this case. 588 */ --- 14 unchanged lines hidden (view full) --- 603 * Called for each memory controller to see if the given address is 604 * mapped to this node (as determined in iaddr_gen) and, if so, which 605 * chip-select on this node responds. 606 */ 607 608/*ARGSUSED*/ 609static int 610mc_patounum(struct mcamd_hdl *hdl, mcamd_node_t *mc, uint64_t pa, |
600 uint32_t synd, int syndtype, mc_unum_t *unump) | 611 uint8_t valid_lo, uint32_t synd, int syndtype, mc_unum_t *unump) |
601{ 602 uint64_t iaddr; 603 mcamd_node_t *cs, *sparecs; 604 int which; 605#ifdef DEBUG 606 mc_unum_t bkdg_unum; 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 612 * difficult to review against the BKDG approach. 613 */ 614 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "BKDG brute-force method begins\n"); | 612{ 613 uint64_t iaddr; 614 mcamd_node_t *cs, *sparecs; 615 int which; 616#ifdef DEBUG 617 mc_unum_t bkdg_unum; 618 int bkdgres; 619 620 /* 621 * We perform the translation twice, once using the brute-force 622 * approach of the BKDG and again using a more elegant but more 623 * difficult to review against the BKDG approach. 624 */ 625 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "BKDG brute-force method begins\n"); |
615 bkdgres = mc_bkdg_patounum(hdl, mc, pa, synd, syndtype, &bkdg_unum); | 626 bkdgres = mc_bkdg_patounum(hdl, mc, pa, valid_lo, synd, 627 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)) { --- 10 unchanged lines hidden (view full) --- 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 | 628 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "BKDG brute-force method ends\n"); 629#endif 630 631 if (iaddr_gen(hdl, mc, pa, &iaddr) < 0) 632 return (-1); /* errno is set for us */ 633 634 for (cs = mcamd_cs_next(hdl, mc, NULL); cs != NULL; 635 cs = mcamd_cs_next(hdl, mc, cs)) { --- 10 unchanged lines hidden (view full) --- 646 * when the swap is done the csbase, csmask and CSBE of the spare 647 * rank do not change - accesses to the bad rank (as nominated in 648 * the Online Spare Control Register) are redirect to the spare. 649 */ 650 if ((sparecs = cs_sparedto(hdl, cs, mc)) != NULL) { 651 cs = sparecs; 652 } 653 |
642 if ((which = mc_whichdimm(hdl, cs, pa, synd, syndtype)) < 0) | 654 if ((which = mc_whichdimm(hdl, cs, pa, valid_lo, synd, 655 syndtype)) < 0) |
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); 650 /* offset is not checked - see note in BKDG algorithm */ --- 20 unchanged lines hidden (view full) --- 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, | 656 return (-1); /* errno is set for us */ 657 658 if (unum_fill(hdl, cs, which, iaddr, unump, 1) < 0) 659 return (-1); /* errno is set for us */ 660 661#ifdef DEBUG 662 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "bkdgres=%d res=0\n", bkdgres); 663 /* offset is not checked - see note in BKDG algorithm */ --- 20 unchanged lines hidden (view full) --- 684 "offset 0x%llx\n", unump->unum_chip, unump->unum_mc, 685 unump->unum_cs, unump->unum_offset); 686 687 return (0); 688} 689 690int 691mcamd_patounum(struct mcamd_hdl *hdl, mcamd_node_t *root, uint64_t pa, |
679 uint32_t synd, int syndtype, mc_unum_t *unump) | 692 uint8_t valid_hi, uint8_t valid_lo, uint32_t synd, int syndtype, 693 mc_unum_t *unump) |
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 | 694{ 695 mcamd_node_t *mc; 696 697 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_patounum: pa=0x%llx, " 698 "synd=0x%x, syndtype=%d\n", pa, synd, syndtype); 699 |
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 */ | 700 if (valid_hi < MC_SYSADDR_MSB) { 701 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_patounum: require " 702 "pa<%d> to be valid\n", MC_SYSADDR_MSB); 703 return (mcamd_set_errno(hdl, EMCAMD_INSUFF_RES)); 704 } 705 |
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)) { | 706 if (!mcamd_synd_validate(hdl, synd, syndtype)) 707 return (mcamd_set_errno(hdl, EMCAMD_SYNDINVALID)); 708 709 for (mc = mcamd_mc_next(hdl, root, NULL); mc != NULL; 710 mc = mcamd_mc_next(hdl, root, mc)) { |
696 if (mc_patounum(hdl, mc, pa, synd, syndtype, unump) == 0) | 711 if (mc_patounum(hdl, mc, pa, valid_lo, synd, 712 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} | 713 return (0); 714 715 if (mcamd_errno(hdl) != EMCAMD_NOADDR) 716 break; 717 } 718 719 return (-1); /* errno is set for us */ 720} |