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}