diff options
author | Zane Shelley <zshelle@us.ibm.com> | 2013-04-08 13:52:35 -0500 |
---|---|---|
committer | A. Patrick Williams III <iawillia@us.ibm.com> | 2013-04-09 16:57:24 -0500 |
commit | 2532f90cd2e11d60a96fa098f99561ac25ecf35d (patch) | |
tree | 03f52e30002318604ae40d7ed7373e8e1b787157 /src/usr/hwpf/hwp/utility_procedures | |
parent | fc990817b98c3bb16c369e365a274ef63a0586c5 (diff) | |
download | talos-hostboot-2532f90cd2e11d60a96fa098f99561ac25ecf35d.tar.gz talos-hostboot-2532f90cd2e11d60a96fa098f99561ac25ecf35d.zip |
Moved mss_maint_cmds to utility_procedures
Change-Id: Ib3a8c8c91bc6e471681a32ebefea4400483c8e6f
Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/3950
Tested-by: Jenkins Server
Reviewed-by: Bradley W. Bishop <bradleyb@us.ibm.com>
Reviewed-by: Sachin Gupta <sgupta2m@in.ibm.com>
Reviewed-by: MIKE J. JONES <mjjones@us.ibm.com>
Reviewed-by: Thi N. Tran <thi@us.ibm.com>
Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
Diffstat (limited to 'src/usr/hwpf/hwp/utility_procedures')
-rw-r--r-- | src/usr/hwpf/hwp/utility_procedures/mss_maint_cmds.C | 5496 | ||||
-rw-r--r-- | src/usr/hwpf/hwp/utility_procedures/utils.mk | 7 |
2 files changed, 5501 insertions, 2 deletions
diff --git a/src/usr/hwpf/hwp/utility_procedures/mss_maint_cmds.C b/src/usr/hwpf/hwp/utility_procedures/mss_maint_cmds.C new file mode 100644 index 000000000..fbab62fb9 --- /dev/null +++ b/src/usr/hwpf/hwp/utility_procedures/mss_maint_cmds.C @@ -0,0 +1,5496 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hwpf/hwp/dram_initialization/mss_memdiag/mss_maint_cmds.C $ */ +/* */ +/* IBM CONFIDENTIAL */ +/* */ +/* COPYRIGHT International Business Machines Corp. 2012,2013 */ +/* */ +/* p1 */ +/* */ +/* Object Code Only (OCO) source materials */ +/* Licensed Internal Code Source Materials */ +/* IBM HostBoot Licensed Internal Code */ +/* */ +/* The source code for this program is not published or otherwise */ +/* divested of its trade secrets, irrespective of what has been */ +/* deposited with the U.S. Copyright Office. */ +/* */ +/* Origin: 30 */ +/* */ +/* IBM_PROLOG_END_TAG */ +// $Id: mss_maint_cmds.C,v 1.20 2013/03/08 22:03:57 gollub Exp $ +//------------------------------------------------------------------------------ +// Don't forget to create CVS comments when you check in your changes! +//------------------------------------------------------------------------------ +// CHANGE HISTORY: +//------------------------------------------------------------------------------ +// Version:| Date: | Author: | Comment: +//---------|----------|---------|----------------------------------------------- +// | 11/02/11 | gollub | Created +// | 12/01/11 | gollub | Fixed problem with end address +// | 03/30/12 | gollub | Made stop condition parm into a mask. +// | | | Added support for both MBAs +// | | | Calculate real start/end address, but run on 2 +// | | | addresses if sim +// | 04/25/12 | gollub | Updated error paths +// | 05/23/12 | gollub | Updates from review. +// | 07/13/12 | gollub | Updates from review. +// 1.8 | 07/16/12 | bellows | added in Id tag +// 1.9 | 07/18/12 | gollub | Updates from review. +// | | | Updates for timebase scrub. +// 1.10 | 07/24/12 | gollub | Fix UE/SUE status bit swap in MBMACA +// | | | Added stop condition enums +// | | | STOP_IMMEDIATE +// | | | ENABLE_CMD_COMPLETE_ATTENTION_ON_CLEAN_AND_ERROR +// | | | Now require cleanupCmd() for super fast read +// | | | to disable rrq fifo mode when done. +// 1.11 | 09/07/12 | gollub | Updates from review. +// | | | Support for more patterns. +// 1.12 | 09/29/12 | gollub | Added mss_restore_DRAM_repairs +// 1.13 | 10/08/12 | gollub | Updated with 12h scrub rate calculation +// 1.14 | 11/02/12 | gollub | Updates from review. +// 1.15 | 11/08/12 | gollub | Added timebase steer cleanup +// | | | Updates to traces. +// 1.16 | 11/21/12 | gollub | Updates from review. +// 1.17 | 12/19/12 | gollub | Added UE isolation +// 1.18 | 01/15/13 | gollub | Added check for valid dimm before calling +// | | | dimmGetBadDqBitmap +// 1.19 | 01/31/13 | gollub | Updated MDI bits for random pattern so +// | | | don't get SUEs +// | | | Added mss_check_steering +// | | | Added mss_do_steering +// | | | Added mss_stopCmd +// | | | Removed cleanupCmd for cmds that didn't use it +// 1.20 | 03/08/13 | gollub | Mask MBSPA[0][8] during increment cmd + +//------------------------------------------------------------------------------ +// Includes +//------------------------------------------------------------------------------ + +#include <mss_maint_cmds.H> +#include <cen_scom_addresses.H> +#include <dimmBadDqBitmapFuncs.H> + +using namespace fapi; + + +//------------------------------------------------------------------------------ +// Constants and enums +//------------------------------------------------------------------------------ + +/** + * @brief Max 8 master ranks per MB + */ +const uint8_t MSS_MAX_RANKS = 8; + +/** + * @brief The number of symbols per rank + */ +const uint8_t MSS_SYMBOLS_PER_RANK = 72; + +/** + * @brief 9 x8 DRAMs we can steer, plus one for no steer option + */ +const uint8_t MSS_X8_STEER_OPTIONS_PER_PORT = 10; + +/** + * @brief 18 x4 DRAMs we can steer on port0, plus one for no steer option + */ +const uint8_t MSS_X4_STEER_OPTIONS_PER_PORT0 = 19; + +/** + * @brief 17 x4 DRAMs we can steer on port1, plus one no steer option + * NOTE: Only 17 DRAMs we can steer since one DRAM is used for the + * ECC spare. + */ +const uint8_t MSS_X4_STEER_OPTIONS_PER_PORT1 = 18; + +/** + * @brief 18 on port0, 17 on port1, plus one no steer option + * NOTE: Can's use ECC spare to fix bad spare DRAMs + */ +const uint8_t MSS_X4_ECC_STEER_OPTIONS = 36; + +/** + * @brief Max 8 patterns + */ +const uint8_t MSS_MAX_PATTERNS = 9; + + +namespace mss_MemConfig +{ +/** + * @brief DRAM size in gigabits, used to determine address range for maint cmds + */ + enum DramSize + { + GBIT_2 = 0, + GBIT_4 = 1, + GBIT_8 = 2, + }; + +/** + * @brief DRAM width, used to determine address range for maint cmds + */ + enum DramWidth + { + X4 = fapi::ENUM_ATTR_EFF_DRAM_WIDTH_X4, + X8 = fapi::ENUM_ATTR_EFF_DRAM_WIDTH_X8, + }; + +/** + * @brief DRAM row, column, and bank bits, used to determine address range + * for maint cmds + */ + enum MemOrg + { + ROW_15 = 0x00007FFF, + ROW_16 = 0x0000FFFF, + COL_10 = 0x000003F8, // c2, c1, c0 always 0 + COL_11 = 0x000007F8, // c2, c1, c0 always 0 + COL_12 = 0x00000FF8, // c2, c1, c0 always 0 + BANK_3 = 0x00000007, + }; + +/** + * @brief Spare DRAM config, used to identify what spares exist + */ + enum SpareDramConfig + { + NO_SPARE = 0, + LOW_NIBBLE = 1, // x4 spare (low nibble: default) + HIGH_NIBBLE = 2, // x4 spare (high nibble: no plan to use) + FULL_BYTE = 3 // x8 dpare + }; + +}; + + + + +static const uint32_t mss_mbaxcr[2]={ + // port0/1 port2/3 + MBAXCR01Q_0x0201140B, MBAXCR23Q_0x0201140C}; + +static const uint32_t mss_mbeccfir[2]={ + // port0/1 port2/3 + MBS_ECC0_MBECCFIR_0x02011440, MBS_ECC1_MBECCFIR_0x02011480}; + +static const uint32_t mss_mbsecc[2]={ + // port0/1 port2/3 + MBS_ECC0_MBSECCQ_0x0201144A, MBS_ECC1_MBSECCQ_0x0201148A}; + +static const uint32_t mss_markStoreRegs[8][2]={ + // port0/1 port2/3 + {MBS_ECC0_MBMS0_0x0201144B, MBS_ECC1_MBMS0_0x0201148B}, + {MBS_ECC0_MBMS1_0x0201144C, MBS_ECC1_MBMS1_0x0201148C}, + {MBS_ECC0_MBMS2_0x0201144D, MBS_ECC1_MBMS2_0x0201148D}, + {MBS_ECC0_MBMS3_0x0201144E, MBS_ECC1_MBMS3_0x0201148E}, + {MBS_ECC0_MBMS4_0x0201144F, MBS_ECC1_MBMS4_0x0201148F}, + {MBS_ECC0_MBMS5_0x02011450, MBS_ECC1_MBMS5_0x02011490}, + {MBS_ECC0_MBMS6_0x02011451, MBS_ECC1_MBMS6_0x02011491}, + {MBS_ECC0_MBMS7_0x02011452, MBS_ECC1_MBMS7_0x02011492}}; + +static const uint32_t mss_mbstr[2]={ + // port0/1 port2/3 + MBS01_MBSTRQ_0x02011655, MBS23_MBSTRQ_0x02011755}; + +static const uint32_t mss_mbmmr[2]={ + // port0/1 port2/3 + MBS_ECC0_MBMMRQ_0x0201145B, MBS_ECC1_MBMMRQ_0x0201149B}; + +static const uint32_t mss_readMuxRegs[8][2]={ + // port0/1 port2/3 + {MBS_ECC0_MBSBS0_0x0201145E, MBS_ECC1_MBSBS0_0x0201149E}, + {MBS_ECC0_MBSBS1_0x0201145F, MBS_ECC1_MBSBS1_0x0201149F}, + {MBS_ECC0_MBSBS2_0x02011460, MBS_ECC1_MBSBS2_0x020114A0}, + {MBS_ECC0_MBSBS3_0x02011461, MBS_ECC1_MBSBS3_0x020114A1}, + {MBS_ECC0_MBSBS4_0x02011462, MBS_ECC1_MBSBS4_0x020114A2}, + {MBS_ECC0_MBSBS5_0x02011463, MBS_ECC1_MBSBS5_0x020114A3}, + {MBS_ECC0_MBSBS6_0x02011464, MBS_ECC1_MBSBS6_0x020114A4}, + {MBS_ECC0_MBSBS7_0x02011465, MBS_ECC1_MBSBS7_0x020114A5}}; + +static const uint32_t mss_writeMuxRegs[8]={ + + MBA01_MBABS0_0x03010440, + MBA01_MBABS1_0x03010441, + MBA01_MBABS2_0x03010442, + MBA01_MBABS3_0x03010443, + MBA01_MBABS4_0x03010444, + MBA01_MBABS5_0x03010445, + MBA01_MBABS6_0x03010446, + MBA01_MBABS7_0x03010447}; + +//------------------------------------------------------------------------------ +// Conversion from symbol index to galois field stored in markstore +//------------------------------------------------------------------------------ +static const uint8_t mss_symbol2Galois[MSS_SYMBOLS_PER_RANK] = + { + 0x80, 0xa0, 0x90, 0xf0, 0x08, 0x0a, 0x09, 0x0f, // symbols 0- 7 + 0x98, 0xda, 0xb9, 0x7f, 0x91, 0xd7, 0xb2, 0x78, // symbols 8-15 + 0x28, 0xea, 0x49, 0x9f, 0x9a, 0xd4, 0xbd, 0x76, // symbols 16-23 + 0x60, 0xb0, 0xc0, 0x20, 0x06, 0x0b, 0x0c, 0x02, // symbols 24-31 + 0xc6, 0xfb, 0x1c, 0x42, 0xca, 0xf4, 0x1d, 0x46, // symbols 32-39 + 0xd6, 0x8b, 0x3c, 0xc2, 0xcb, 0xf3, 0x1f, 0x4e, // symbols 40-47 + 0xe0, 0x10, 0x50, 0xd0, 0x0e, 0x01, 0x05, 0x0d, // symbols 48-55 + 0x5e, 0x21, 0xa5, 0x3d, 0x5b, 0x23, 0xaf, 0x3e, // symbols 56-63 + 0xfe, 0x61, 0x75, 0x5d, 0x51, 0x27, 0xa2, 0x38, // symbols 64-71 + }; + + + +static const uint8_t mss_x8dramSparePort0Index_to_symbol[MSS_X8_STEER_OPTIONS_PER_PORT]={ + // symbol + MSS_INVALID_SYMBOL, // Port0 DRAM spare not used + 68, // DRAM 17 (x8) + 64, // DRAM 16 (x8) + 60, // DRAM 15 (x8) + 56, // DRAM 14 (x8) + 52, // DRAM 13 (x8) + 48, // DRAM 12 (x8) + 44, // DRAM 11 (x8) + 40, // DRAM 10 (x8) + 4}; // DRAM 1 (x8) + +static const uint8_t mss_x4dramSparePort0Index_to_symbol[MSS_X4_STEER_OPTIONS_PER_PORT0]={ + // symbol + MSS_INVALID_SYMBOL, // Port0 DRAM spare not used + 70, // DRAM 35 (x4) + 68, // DRAM 34 (x4) + 66, // DRAM 33 (x4) + 64, // DRAM 32 (x4) + 62, // DRAM 31 (x4) + 60, // DRAM 30 (x4) + 58, // DRAM 29 (x4) + 56, // DRAM 28 (x4) + 54, // DRAM 27 (x4) + 52, // DRAM 26 (x4) + 50, // DRAM 25 (x4) + 48, // DRAM 24 (x4) + 46, // DRAM 23 (x4) + 44, // DRAM 22 (x4) + 42, // DRAM 21 (x4) + 40, // DRAM 20 (x4) + 6, // DRAM 3 (x4) + 4}; // DRAM 2 (x4) + + + +static const uint8_t mss_x8dramSparePort1Index_to_symbol[MSS_X8_STEER_OPTIONS_PER_PORT]={ + // symbol + MSS_INVALID_SYMBOL, // Port1 DRAM spare not used + 36, // DRAM 9 (x8) + 32, // DRAM 8 (x8) + 28, // DRAM 7 (x8) + 24, // DRAM 6 (x8) + 20, // DRAM 5 (x8) + 16, // DRAM 4 (x8) + 12, // DRAM 3 (x8) + 8, // DRAM 2 (x8) + 0}; // DRAM 0 (x8) + + + +static const uint8_t mss_x4dramSparePort1Index_to_symbol[MSS_X4_STEER_OPTIONS_PER_PORT1]={ + // symbol + MSS_INVALID_SYMBOL, // Port1 DRAM spare not used + 38, // DRAM 19 (x4) + 36, // DRAM 18 (x4) + 34, // DRAM 17 (x4) + 32, // DRAM 16 (x4) + 30, // DRAM 15 (x4) + 28, // DRAM 14 (x4) + 26, // DRAM 13 (x4) + 24, // DRAM 12 (x4) + 22, // DRAM 11 (x4) + 20, // DRAM 10 (x4) + 18, // DRAM 9 (x4) + 16, // DRAM 8 (x4) + 14, // DRAM 7 (x4) + 12, // DRAM 6 (x4) + 10, // DRAM 5 (x4) + 8, // DRAM 4 (x4) + 2}; // DRAM 1 (x4) + // NOTE: DRAM 0 (x4) (symbols 0,1) on Port1 is used for the ECC spare, + // so can't use DRAM spare to fix DRAM 0. + + + +static const uint8_t mss_eccSpareIndex_to_symbol[MSS_X4_ECC_STEER_OPTIONS]={ + // symbol + MSS_INVALID_SYMBOL, // ECC spare not used + 70, // DRAM 35 (x4) + 68, // DRAM 34 (x4) + 66, // DRAM 33 (x4) + 64, // DRAM 32 (x4) + 62, // DRAM 31 (x4) + 60, // DRAM 30 (x4) + 58, // DRAM 29 (x4) + 56, // DRAM 28 (x4) + 54, // DRAM 27 (x4) + 52, // DRAM 26 (x4) + 50, // DRAM 25 (x4) + 48, // DRAM 24 (x4) + 46, // DRAM 23 (x4) + 44, // DRAM 22 (x4) + 42, // DRAM 21 (x4) + 40, // DRAM 20 (x4) + 38, // DRAM 19 (x4) + 36, // DRAM 18 (x4) + 34, // DRAM 17 (x4) + 32, // DRAM 16 (x4) + 30, // DRAM 15 (x4) + 28, // DRAM 14 (x4) + 26, // DRAM 13 (x4) + 24, // DRAM 12 (x4) + 22, // DRAM 11 (x4) + 20, // DRAM 10 (x4) + 18, // DRAM 9 (x4) + 16, // DRAM 8 (x4) + 14, // DRAM 7 (x4) + 12, // DRAM 6 (x4) + 10, // DRAM 5 (x4) + 8, // DRAM 4 (x4) + 6, // DRAM 3 (x4) + 4, // DRAM 2 (x4) + 2}; // DRAM 1 (x4) + // NOTE: DRAM 0 (x4) (symbols 0,1) used for the ECC spare. + // NOTE: Can't use ECC spare to fix bad spare DRAMs on Port0 or Port1 + +// TODO: Update with actual patterns from Luis Lastras when they are ready +static const uint32_t mss_maintBufferData[MSS_MAX_PATTERNS][16][2]={ + +// PATTERN_0 DEBUG +/* + {{0x00000000, 0x10000000}, + {0x01000000, 0x11000000}, + {0x02000000, 0x12000000}, + {0x03000000, 0x13000000}, + {0x04000000, 0x14000000}, + {0x05000000, 0x15000000}, + {0x06000000, 0x16000000}, + {0x07000000, 0x17000000}, + {0x08000000, 0x18000000}, + {0x09000000, 0x19000000}, + {0x0a000000, 0x1a000000}, + {0x0b000000, 0x1b000000}, + {0x0c000000, 0x1c000000}, + {0x0d000000, 0x1d000000}, + {0x0e000000, 0x1e000000}, + {0x0f000000, 0x1f000000}}, +*/ + + +// PATTERN_0 + {{0x00000000, 0x00000000}, + {0x00000000, 0x00000000}, + {0x00000000, 0x00000000}, + {0x00000000, 0x00000000}, + {0x00000000, 0x00000000}, + {0x00000000, 0x00000000}, + {0x00000000, 0x00000000}, + {0x00000000, 0x00000000}, + {0x00000000, 0x00000000}, + {0x00000000, 0x00000000}, + {0x00000000, 0x00000000}, + {0x00000000, 0x00000000}, + {0x00000000, 0x00000000}, + {0x00000000, 0x00000000}, + {0x00000000, 0x00000000}, + {0x00000000, 0x00000000}}, + +// PATTERN_1 + {{0xffffffff, 0xffffffff}, + {0xffffffff, 0xffffffff}, + {0xffffffff, 0xffffffff}, + {0xffffffff, 0xffffffff}, + {0xffffffff, 0xffffffff}, + {0xffffffff, 0xffffffff}, + {0xffffffff, 0xffffffff}, + {0xffffffff, 0xffffffff}, + {0xffffffff, 0xffffffff}, + {0xffffffff, 0xffffffff}, + {0xffffffff, 0xffffffff}, + {0xffffffff, 0xffffffff}, + {0xffffffff, 0xffffffff}, + {0xffffffff, 0xffffffff}, + {0xffffffff, 0xffffffff}, + {0xffffffff, 0xffffffff}}, + +// PATTERN_2 + {{0xf0f0f0f0, 0xf0f0f0f0}, + {0xf0f0f0f0, 0xf0f0f0f0}, + {0xf0f0f0f0, 0xf0f0f0f0}, + {0xf0f0f0f0, 0xf0f0f0f0}, + {0xf0f0f0f0, 0xf0f0f0f0}, + {0xf0f0f0f0, 0xf0f0f0f0}, + {0xf0f0f0f0, 0xf0f0f0f0}, + {0xf0f0f0f0, 0xf0f0f0f0}, + {0xf0f0f0f0, 0xf0f0f0f0}, + {0xf0f0f0f0, 0xf0f0f0f0}, + {0xf0f0f0f0, 0xf0f0f0f0}, + {0xf0f0f0f0, 0xf0f0f0f0}, + {0xf0f0f0f0, 0xf0f0f0f0}, + {0xf0f0f0f0, 0xf0f0f0f0}, + {0xf0f0f0f0, 0xf0f0f0f0}, + {0xf0f0f0f0, 0xf0f0f0f0}}, + +// PATTERN_3 + {{0x0f0f0f0f, 0x0f0f0f0f}, + {0x0f0f0f0f, 0x0f0f0f0f}, + {0x0f0f0f0f, 0x0f0f0f0f}, + {0x0f0f0f0f, 0x0f0f0f0f}, + {0x0f0f0f0f, 0x0f0f0f0f}, + {0x0f0f0f0f, 0x0f0f0f0f}, + {0x0f0f0f0f, 0x0f0f0f0f}, + {0x0f0f0f0f, 0x0f0f0f0f}, + {0x0f0f0f0f, 0x0f0f0f0f}, + {0x0f0f0f0f, 0x0f0f0f0f}, + {0x0f0f0f0f, 0x0f0f0f0f}, + {0x0f0f0f0f, 0x0f0f0f0f}, + {0x0f0f0f0f, 0x0f0f0f0f}, + {0x0f0f0f0f, 0x0f0f0f0f}, + {0x0f0f0f0f, 0x0f0f0f0f}, + {0x0f0f0f0f, 0x0f0f0f0f}}, + +// PATTERN_4 + {{0xaaaaaaaa, 0xaaaaaaaa}, + {0xaaaaaaaa, 0xaaaaaaaa}, + {0xaaaaaaaa, 0xaaaaaaaa}, + {0xaaaaaaaa, 0xaaaaaaaa}, + {0xaaaaaaaa, 0xaaaaaaaa}, + {0xaaaaaaaa, 0xaaaaaaaa}, + {0xaaaaaaaa, 0xaaaaaaaa}, + {0xaaaaaaaa, 0xaaaaaaaa}, + {0xaaaaaaaa, 0xaaaaaaaa}, + {0xaaaaaaaa, 0xaaaaaaaa}, + {0xaaaaaaaa, 0xaaaaaaaa}, + {0xaaaaaaaa, 0xaaaaaaaa}, + {0xaaaaaaaa, 0xaaaaaaaa}, + {0xaaaaaaaa, 0xaaaaaaaa}, + {0xaaaaaaaa, 0xaaaaaaaa}, + {0xaaaaaaaa, 0xaaaaaaaa}}, + +// PATTERN_5 + {{0x55555555, 0x55555555}, + {0x55555555, 0x55555555}, + {0x55555555, 0x55555555}, + {0x55555555, 0x55555555}, + {0x55555555, 0x55555555}, + {0x55555555, 0x55555555}, + {0x55555555, 0x55555555}, + {0x55555555, 0x55555555}, + {0x55555555, 0x55555555}, + {0x55555555, 0x55555555}, + {0x55555555, 0x55555555}, + {0x55555555, 0x55555555}, + {0x55555555, 0x55555555}, + {0x55555555, 0x55555555}, + {0x55555555, 0x55555555}, + {0x55555555, 0x55555555}}, + +// PATTERN_6 + {{0xcccccccc, 0xcccccccc}, + {0xcccccccc, 0xcccccccc}, + {0xcccccccc, 0xcccccccc}, + {0xcccccccc, 0xcccccccc}, + {0xcccccccc, 0xcccccccc}, + {0xcccccccc, 0xcccccccc}, + {0xcccccccc, 0xcccccccc}, + {0xcccccccc, 0xcccccccc}, + {0xcccccccc, 0xcccccccc}, + {0xcccccccc, 0xcccccccc}, + {0xcccccccc, 0xcccccccc}, + {0xcccccccc, 0xcccccccc}, + {0xcccccccc, 0xcccccccc}, + {0xcccccccc, 0xcccccccc}, + {0xcccccccc, 0xcccccccc}, + {0xcccccccc, 0xcccccccc}}, + +// PATTERN_7 + {{0x33333333, 0x33333333}, + {0x33333333, 0x33333333}, + {0x33333333, 0x33333333}, + {0x33333333, 0x33333333}, + {0x33333333, 0x33333333}, + {0x33333333, 0x33333333}, + {0x33333333, 0x33333333}, + {0x33333333, 0x33333333}, + {0x33333333, 0x33333333}, + {0x33333333, 0x33333333}, + {0x33333333, 0x33333333}, + {0x33333333, 0x33333333}, + {0x33333333, 0x33333333}, + {0x33333333, 0x33333333}, + {0x33333333, 0x33333333}, + {0x33333333, 0x33333333}}, + +// PATTERN_8: random seed + {{0x12345678, 0x87654321}, + {0x12345678, 0x87654321}, + {0x12345678, 0x87654321}, + {0x12345678, 0x87654321}, + {0x12345678, 0x87654321}, + {0x12345678, 0x87654321}, + {0x12345678, 0x87654321}, + {0x12345678, 0x87654321}, + {0x12345678, 0x87654321}, + {0x12345678, 0x87654321}, + {0x12345678, 0x87654321}, + {0x12345678, 0x87654321}, + {0x12345678, 0x87654321}, + {0x12345678, 0x87654321}, + {0x12345678, 0x87654321}, + {0x12345678, 0x87654321}}}; + + + +// TODO: Update with actual patterns from Luis Lastras when they are ready +static const uint8_t mss_65thByte[MSS_MAX_PATTERNS][4]={ + +// bit1=tag0_2, bit2=tag1_3, bit3=MDI + +// PATTERN_0 - verified + {0x00, // 1st 64B of cachline: tag0=0, tag1=0, MDI=0 + 0x00, // 1st 64B of cachline: tag2=0, tag3=0, MDI=0 + 0x00, // 2nd 64B of cachline: tag0=0, tag1=0, MDI=0 + 0x00}, // 2nd 64B of cachline: tag2=0, tag3=0, MDI=0 + +// PATTERN_1 - verified + {0xF0, // 1st 64B of cachline: tag0=1, tag1=1, MDI=1 + 0x70, // 1st 64B of cachline: tag2=1, tag3=1, MDI=1 + 0xF0, // 2nd 64B of cachline: tag0=1, tag1=1, MDI=1 + 0x70}, // 2nd 64B of cachline: tag2=1, tag3=1, MDI=1 + +// PATTERN_2 - verified + {0x70, // 1st 64B of cachline: tag0=1, tag1=1, MDI=1 + 0x00, // 1st 64B of cachline: tag2=0, tag3=0, MDI=0 + 0x70, // 2nd 64B of cachline: tag0=1, tag1=1, MDI=1 + 0x00}, // 2nd 64B of cachline: tag2=0, tag3=0, MDI=0 + +// PATTERN_3 - verified + {0x80, // 1st 64B of cachline: tag0=0, tag1=0, MDI=0 + 0x70, // 1st 64B of cachline: tag2=1, tag3=1, MDI=1 + 0x80, // 2nd 64B of cachline: tag0=0, tag1=0, MDI=0 + 0x70}, // 2nd 64B of cachline: tag2=1, tag3=1, MDI=1 + +// PATTERN_4 - verified + {0xB0, // 1st 64B of cachline: tag0=0, tag1=1, MDI=1 + 0xD0, // 1st 64B of cachline: tag2=1, tag3=0, MDI=1 + 0xA0, // 2nd 64B of cachline: tag0=0, tag1=1, MDI=0 + 0x40}, // 2nd 64B of cachline: tag2=1, tag3=0, MDI=0 + +// PATTERN_5 - verified + {0xE0, // 1st 64B of cachline: tag0=1, tag1=0, MDI=0 + 0x20, // 1st 64B of cachline: tag2=0, tag3=1, MDI=0 + 0x50, // 2nd 64B of cachline: tag0=1, tag1=0, MDI=1 + 0x30}, // 2nd 64B of cachline: tag2=0, tag3=1, MDI=1 + +// PATTERN_6 - verified + {0x70, // 1st 64B of cachline: tag0=1, tag1=1, MDI=1 + 0xC0, // 1st 64B of cachline: tag2=1, tag3=0, MDI=0 + 0x60, // 2nd 64B of cachline: tag0=1, tag1=1, MDI=0 + 0x50}, // 2nd 64B of cachline: tag2=1, tag3=0, MDI=1 + +// PATTERN_7 - verified + {0x20, // 1st 64B of cachline: tag0=0, tag1=1, MDI=0 + 0x70, // 1st 64B of cachline: tag2=1, tag3=1, MDI=1 + 0x30, // 2nd 64B of cachline: tag0=0, tag1=1, MDI=1 + 0xE0}, // 2nd 64B of cachline: tag2=1, tag3=1, MDI=0 + +// PATTERN_8: random seed + {0x20, // 1st 64B of cachline: tag0=0, tag1=1, MDI=0 + 0x60, // 1st 64B of cachline: tag2=1, tag3=1, MDI=0 + 0x30, // 2nd 64B of cachline: tag0=0, tag1=1, MDI=1 + 0x70}}; // 2nd 64B of cachline: tag2=1, tag3=1, MDI=1 + +// TODO: Update with actual patterns from Luis Lastras when they are ready +static const uint32_t mss_ECC[MSS_MAX_PATTERNS][4]={ + +// bit 4:15 ECC_c6_c5_c4, bit 16:31 ECC_c3_c2_c1_c0 + +// PATTERN_0 - verified + {0x00000000, // 1st 64B of cachline + 0x00000000, // 1st 64B of cachline + 0x00000000, // 2nd 64B of cachline + 0x00000000}, // 2nd 64B of cachline + +// PATTERN_1 - verified + {0x0DA49500, // 1st 64B of cachline + 0x0234A60E, // 1st 64B of cachline + 0x0DA49500, // 2nd 64B of cachline + 0x0234A60E}, // 2nd 64B of cachline + +// PATTERN_2 - verified + {0x08A0AB54, // 1st 64B of cachline + 0x05CD9A13, // 1st 64B of cachline + 0x08A0AB54, // 2nd 64B of cachline + 0x05CD9A13}, // 2nd 64B of cachline + +// PATTERN_3 - verified + {0x05043E54, // 1st 64B of cachline + 0x07F93C1D, // 1st 64B of cachline + 0x05043E54, // 2nd 64B of cachline + 0x07F93C1D}, // 2nd 64B of cachline + +// PATTERN_4 - verified + {0x021C0F3D, // 1st 64B of cachline + 0x04332068, // 1st 64B of cachline + 0x0C33F1DA, // 2nd 64B of cachline + 0x0FF3F7AF}, // 2nd 64B of cachline + +// PATTERN_5 - verified + {0x04CA8334, // 1st 64B of cachline + 0x04F3D0DA, // 1st 64B of cachline + 0x019764DA, // 2nd 64B of cachline + 0x0DC751A1}, // 2nd 64B of cachline + +// PATTERN_6 - verified + {0x0CF6B55C, // 1st 64B of cachline + 0x08CCE671, // 1st 64B of cachline + 0x02D94BBB, // 2nd 64B of cachline + 0x030C31B6}, // 2nd 64B of cachline + +// PATTERN_7 - verified + {0x09150CD1, // 1st 64B of cachline + 0x0F9D48C9, // 1st 64B of cachline + 0x073AF236, // 2nd 64B of cachline + 0x045D9F0E}, // 2nd 64B of cachline + +// PATTERN_8: random + {0x00000000, // 1st 64B of cachline + 0x00000000, // 1st 64B of cachline + 0x00000000, // 2nd 64B of cachline + 0x00000000}}; // 2nd 64B of cachline + + + +//------------------------------------------------------------------------------ +// Parent class +//------------------------------------------------------------------------------ + + + +//--------------------------------------------------------- +// mss_MaintCmd Constructor +//--------------------------------------------------------- +mss_MaintCmd::mss_MaintCmd(const fapi::Target & i_target, + const ecmdDataBufferBase & i_startAddr, + const ecmdDataBufferBase & i_endAddr, + uint32_t i_stopCondition, + bool i_poll, + CmdType i_cmdType ) : + iv_target( i_target ), + iv_startAddr( i_startAddr ), + iv_endAddr( i_endAddr ), + iv_stopCondition( i_stopCondition), + iv_poll (i_poll), + iv_cmdType(i_cmdType){} + + +//--------------------------------------------------------- +// mss_stopCmd +//--------------------------------------------------------- +fapi::ReturnCode mss_MaintCmd::stopCmd() +{ + fapi::ReturnCode l_rc; + uint32_t l_ecmd_rc = 0; + ecmdDataBufferBase l_mbmsrq(64); + ecmdDataBufferBase l_mbmccq(64); + ecmdDataBufferBase l_mbmacaq(64); + + FAPI_INF("ENTER mss_MaintCmd::stopCmd()"); + + // Read MBMSRQ + l_rc = fapiGetScom(iv_target, MBA01_MBMSRQ_0x0301060C, l_mbmsrq); + if(l_rc) return l_rc; + + // If MBMSRQ[0], maint_cmd_in_progress, stop the cmd + if (l_mbmsrq.isBitSet(0)) + { + // Read MBMCCQ + l_rc = fapiGetScom(iv_target, MBA01_MBMCCQ_0x0301060B, l_mbmccq); + if(l_rc) return l_rc; + + // Set bit 1 to force the cmd to stop + l_ecmd_rc |= l_mbmccq.setBit(1); + if(l_ecmd_rc) + { + l_rc.setEcmdError(l_ecmd_rc); + return l_rc; + } + + // Write MBMCCQ + l_rc = fapiPutScom(iv_target, MBA01_MBMCCQ_0x0301060B, l_mbmccq); + if(l_rc) return l_rc; + + // Read MBMSRQ + l_rc = fapiGetScom(iv_target, MBA01_MBMSRQ_0x0301060C, l_mbmsrq); + if(l_rc) return l_rc; + + // If cmd didn't stop as expected + if (l_mbmsrq.isBitSet(0)) + { + FAPI_ERR("MBMSRQ[0] = 1, unsuccessful forced maint cmd stop."); + + // Calling out MBA target high, deconfig, gard + const fapi::Target & MBA = iv_target; + // FFDC: Capture register we used to stop cmd + ecmdDataBufferBase & MBMCC = l_mbmccq; + // FFDC: Capture register we are checking + ecmdDataBufferBase & MBMSR = l_mbmsrq; + // FFDC: Capture command type we are trying to run + const mss_MaintCmd::CmdType & CMD_TYPE = iv_cmdType; + + // Create new log + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_UNSUCCESSFUL_FORCED_MAINT_CMD_STOP); + return l_rc; + } + } + + // Store the address we stopped at in iv_startAddr + l_rc = fapiGetScom(iv_target, MBA01_MBMACAQ_0x0301060D, iv_startAddr); + if(l_rc) return l_rc; + + // Only 0-36 are valid address bits so clear the rest, 37-63 + l_ecmd_rc |= iv_startAddr.clearBit(37,27); + if(l_ecmd_rc) + { + l_rc.setEcmdError(l_ecmd_rc); + return l_rc; + } + + + FAPI_INF("EXIT mss_MaintCmd::stopCmd()"); + return l_rc; +} + + +//--------------------------------------------------------- +// mss_cleanupCmd +//--------------------------------------------------------- +fapi::ReturnCode mss_MaintCmd::cleanupCmd() +{ + fapi::ReturnCode l_rc; + FAPI_INF("ENTER mss_MaintCmd::cleanupCmd()"); + + + + FAPI_INF("EXIT mss_MaintCmd::cleanupCmd()"); + return l_rc; +} + + +//--------------------------------------------------------- +// mss_preConditionCheck +//--------------------------------------------------------- +fapi::ReturnCode mss_MaintCmd::preConditionCheck() +{ + fapi::ReturnCode l_rc; + ecmdDataBufferBase l_mbmccq(64); + ecmdDataBufferBase l_mbmsrq(64); + ecmdDataBufferBase l_mbaxcr(64); + ecmdDataBufferBase l_ccs_modeq(64); + ecmdDataBufferBase l_mbsecc(64); + ecmdDataBufferBase l_mbmct(64); + + FAPI_INF("ENTER mss_MaintCmd::preConditionCheck()"); + + // Get Centaur target for the given MBA + l_rc = fapiGetParentChip(iv_target, iv_targetCentaur); + if(l_rc) + { + FAPI_ERR("Error getting Centaur parent target for the given MBA"); + return l_rc; + } + + // Get MBA position: 0 = mba01, 1 = mba23 + l_rc = FAPI_ATTR_GET(ATTR_CHIP_UNIT_POS, &iv_target, iv_mbaPosition); + if(l_rc) + { + FAPI_ERR("Error getting MBA position"); + return l_rc; + } + + // Read MBMCCQ + l_rc = fapiGetScom(iv_target, MBA01_MBMCCQ_0x0301060B, l_mbmccq); + if(l_rc) return l_rc; + + // Read MBMSRQ + l_rc = fapiGetScom(iv_target, MBA01_MBMSRQ_0x0301060C, l_mbmsrq); + if(l_rc) return l_rc; + + // Read MBAXCRn + l_rc = fapiGetScom(iv_targetCentaur, mss_mbaxcr[iv_mbaPosition], l_mbaxcr); + if(l_rc) return l_rc; + + // Read CCS_MODEQ + l_rc = fapiGetScom(iv_target, MEM_MBA01_CCS_MODEQ_0x030106A7, l_ccs_modeq); + if(l_rc) return l_rc; + + // Read MBSECC + l_rc = fapiGetScom(iv_targetCentaur, mss_mbsecc[iv_mbaPosition], l_mbsecc); + if(l_rc) return l_rc; + + // Read MBMCT[0:4], cmd type, for FFDC + l_rc = fapiGetScom(iv_target, MBA01_MBMCTQ_0x0301060A, l_mbmct); + if(l_rc) return l_rc; + + + // Check for MBMCCQ[0], maint_cmd_start, to be reset by hw. + if (l_mbmccq.isBitSet(0)) + { + + FAPI_ERR("MBMCCQ[0]: maint_cmd_start not reset by hw."); + + // Calling out MBA target high, deconfig, gard + const fapi::Target & MBA = iv_target; + // FFDC: Capture register we are checking + ecmdDataBufferBase & MBMCC = l_mbmccq; + // FFDC: Capture command type we are trying to run + const mss_MaintCmd::CmdType & CMD_TYPE = iv_cmdType; + // FFDC: MBMCT[0:4] contains the cmd type previously run + ecmdDataBufferBase & MBMCT = l_mbmct; + + // Create new log + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_START_NOT_RESET); + } + + // Check for MBMCCQ[1], maint_cmd_stop, to be reset by hw. + if (l_mbmccq.isBitSet(1)) + { + // Log previous error before creating new log + if (l_rc) fapiLogError(l_rc); + + FAPI_ERR("MBMCCQ[1]: maint_cmd_stop not reset by hw."); + + // Calling out MBA target high, deconfig, gard + const fapi::Target & MBA = iv_target; + // FFDC: Capture register we are checking + ecmdDataBufferBase & MBMCC = l_mbmccq; + // FFDC: Capture command type we are trying to run + const mss_MaintCmd::CmdType & CMD_TYPE = iv_cmdType; + // FFDC: MBMCT[0:4] contains the cmd type previously run + ecmdDataBufferBase & MBMCT = l_mbmct; + + // Create new log + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_STOP_NOT_RESET); + } + + // Check for MBMSRQ[0], maint_cmd_in_progress, to be reset. + if (l_mbmsrq.isBitSet(0)) + { + // Log previous error before creating new log + if (l_rc) fapiLogError(l_rc); + + FAPI_ERR("MBMSRQ[0]: Can't start new cmd if previous cmd still in progress."); + + // TODO: Calling out FW high + // Calling out MBA target low, deconfig, gard + const fapi::Target & MBA = iv_target; + // FFDC: Capture register we are checking + ecmdDataBufferBase & MBMSR = l_mbmsrq; + // FFDC: Capture command type we are trying to run + const mss_MaintCmd::CmdType & CMD_TYPE = iv_cmdType; + // FFDC: MBMCT[0:4] contains the cmd type previously run + ecmdDataBufferBase & MBMCT = l_mbmct; + + // Create new log + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_CMD_IN_PROGRESS); + } + + // Check MBAXCRn, to show memory configured behind this MBA + if (l_mbaxcr.isBitClear(0,4)) + { + // Log previous error before creating new log + if (l_rc) fapiLogError(l_rc); + + FAPI_ERR("MBAXCRn[0:3] = 0, meaning no memory configured behind this MBA."); + + // TODO: Calling out FW high + // FFDC: MBA target + const fapi::Target & MBA = iv_target; + // FFDC: Capture register we are checking + ecmdDataBufferBase & MBAXCR = l_mbaxcr; + + // Create new log + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_NO_MEM_CNFG); + } + + // Check CCS_MODEQ[29] to make sure mux switched from CCS to mainline + if (l_ccs_modeq.isBitSet(29)) + { + // Log previous error before creating new log + if (l_rc) fapiLogError(l_rc); + + FAPI_ERR("CCS_MODEQ[29] = 1, meaning mux set for CCS instead of mainline."); + + // TODO: Calling out FW high + // FFDC: MBA target + const fapi::Target & MBA = iv_target; + // FFDC: Capture register we are checking + ecmdDataBufferBase & CCS_MODE = l_ccs_modeq; + // FFDC: Capture command type we are trying to run + const mss_MaintCmd::CmdType & CMD_TYPE = iv_cmdType; + + // Create new log + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_CCS_MUX_NOT_MAINLINE); + } + + // Check MBSECC[0] = 0, to make sure ECC check/correct is enabled + if (l_mbsecc.isBitSet(0)) + { + // Log previous error before creating new log + if (l_rc) fapiLogError(l_rc); + + FAPI_ERR("MBSECC[0] = 1, meaning ECC check/correct disabled."); + + // TODO: Calling out FW high + // FFDC: MBA target + const fapi::Target & MBA = iv_target; + // FFDC: Capture register we are checking + ecmdDataBufferBase & MBSECC = l_mbsecc; + // FFDC: Capture command type we are trying to run + const mss_MaintCmd::CmdType & CMD_TYPE = iv_cmdType; + + // Create new log + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_ECC_DISABLED); + } + + + FAPI_INF("EXIT mss_MaintCmd::preConditionCheck()"); + return l_rc; +} + + +//--------------------------------------------------------- +// mss_loadCmdType +//--------------------------------------------------------- +fapi::ReturnCode mss_MaintCmd::loadCmdType() +{ + fapi::ReturnCode l_rc; + uint32_t l_ecmd_rc = 0; + ecmdDataBufferBase l_data(64); + + FAPI_INF("ENTER mss_MaintCmd::loadCmdType()"); + + l_rc = fapiGetScom(iv_target, MBA01_MBMCTQ_0x0301060A, l_data); + if(l_rc) return l_rc; + l_ecmd_rc |= l_data.insert( (uint32_t)iv_cmdType, 0, 5, 32-5 ); + + // NOTE: Setting super fast address increment mode, where COL bits are LSB. + // Valid for all cmds. + l_ecmd_rc |= l_data.setBit(5); + if(l_ecmd_rc) + { + l_rc.setEcmdError(l_ecmd_rc); + return l_rc; + } + l_rc = fapiPutScom(iv_target, MBA01_MBMCTQ_0x0301060A, l_data); + if(l_rc) return l_rc; + + FAPI_INF("EXIT mss_MaintCmd::loadCmdType()"); + return l_rc; +} + + + +//--------------------------------------------------------- +// mss_loadStartAddress +//--------------------------------------------------------- +fapi::ReturnCode mss_MaintCmd::loadStartAddress() +{ + fapi::ReturnCode l_rc; + uint32_t l_ecmd_rc = 0; + ecmdDataBufferBase l_data(64); + + FAPI_INF("ENTER mss_MaintCmd::loadStartAddress()"); + + l_rc = fapiGetScom(iv_target, MBA01_MBMACAQ_0x0301060D, l_data); + if(l_rc) return l_rc; + + // Load address bits 0:39 + l_ecmd_rc |= l_data.insert( iv_startAddr, 0, 40, 0 ); + + // Clear error status bits 40:46 + l_ecmd_rc |= l_data.clearBit(40,7); + + if(l_ecmd_rc) + { + l_rc.setEcmdError(l_ecmd_rc); + return l_rc; + } + l_rc = fapiPutScom(iv_target, MBA01_MBMACAQ_0x0301060D, l_data); + if(l_rc) return l_rc; + + FAPI_INF("EXIT mss_MaintCmd::loadStartAddress()"); + return l_rc; +} + + +//--------------------------------------------------------- +// mss_loadEndAddress +//--------------------------------------------------------- +fapi::ReturnCode mss_MaintCmd::loadEndAddress() +{ + fapi::ReturnCode l_rc; + uint32_t l_ecmd_rc = 0; + ecmdDataBufferBase l_data(64); + + FAPI_INF("ENTER mss_MaintCmd::loadEndAddress()"); + + l_rc = fapiGetScom(iv_target, MBA01_MBMEAQ_0x0301060E, l_data); + if(l_rc) return l_rc; + + l_ecmd_rc |= l_data.insert( iv_endAddr, 0, 40, 0 ); + if(l_ecmd_rc) + { + l_rc.setEcmdError(l_ecmd_rc); + return l_rc; + } + l_rc = fapiPutScom(iv_target, MBA01_MBMEAQ_0x0301060E, l_data); + if(l_rc) return l_rc; + + FAPI_INF("EXIT mss_MaintCmd::loadEndAddress()"); + return l_rc; +} + + +//--------------------------------------------------------- +// mss_loadStopCondMask +//--------------------------------------------------------- +fapi::ReturnCode mss_MaintCmd::loadStopCondMask() +{ + fapi::ReturnCode l_rc; + uint32_t l_ecmd_rc = 0; + ecmdDataBufferBase l_mbasctlq(64); + + FAPI_INF("ENTER mss_MaintCmd::loadStopCondMask()"); + + // Get stop conditions from MBASCTLQ + l_rc = fapiGetScom(iv_target, MBA01_MBASCTLQ_0x0301060F, l_mbasctlq); + if(l_rc) return l_rc; + + // Start by clearing all bits 0:12 and bit 16 + l_ecmd_rc |= l_mbasctlq.clearBit(0,13); + l_ecmd_rc |= l_mbasctlq.clearBit(16); + + // Enable stop immediate + if ( 0 != (iv_stopCondition & STOP_IMMEDIATE) ) + l_ecmd_rc |= l_mbasctlq.setBit(0); + + // Enable stop end of rank + if ( 0 != (iv_stopCondition & STOP_END_OF_RANK) ) + l_ecmd_rc |= l_mbasctlq.setBit(1); + + // Stop on hard NCE ETE + if ( 0 != (iv_stopCondition & STOP_ON_HARD_NCE_ETE) ) + l_ecmd_rc |= l_mbasctlq.setBit(2); + + // Stop on intermittent NCE ETE + if ( 0 != (iv_stopCondition & STOP_ON_INT_NCE_ETE) ) + l_ecmd_rc |= l_mbasctlq.setBit(3); + + // Stop on soft NCE ETE + if ( 0 != (iv_stopCondition & STOP_ON_SOFT_NCE_ETE) ) + l_ecmd_rc |= l_mbasctlq.setBit(4); + + // Stop on SCE + if ( 0 != (iv_stopCondition & STOP_ON_SCE) ) + l_ecmd_rc |= l_mbasctlq.setBit(5); + + // Stop on MCE + if ( 0 != (iv_stopCondition & STOP_ON_MCE) ) + l_ecmd_rc |= l_mbasctlq.setBit(6); + + // Stop on retry CE ETE + if ( 0 != (iv_stopCondition & STOP_ON_RETRY_CE_ETE) ) + l_ecmd_rc |= l_mbasctlq.setBit(7); + + // Stop on MPE + if ( 0 != (iv_stopCondition & STOP_ON_MPE) ) + l_ecmd_rc |= l_mbasctlq.setBit(8); + + // Stop on UE + if ( 0 != (iv_stopCondition & STOP_ON_UE) ) + l_ecmd_rc |= l_mbasctlq.setBit(9); + + // Stop on end address + if ( 0 != (iv_stopCondition & STOP_ON_END_ADDRESS) ) + l_ecmd_rc |= l_mbasctlq.setBit(10); + + // Enable command complete attention + if ( 0 != (iv_stopCondition & ENABLE_CMD_COMPLETE_ATTENTION) ) + l_ecmd_rc |= l_mbasctlq.setBit(11); + + // Stop on SUE + if ( 0 != (iv_stopCondition & STOP_ON_SUE) ) + l_ecmd_rc |= l_mbasctlq.setBit(12); + + // Enable command complete attention on clean and error + if ( 0 != (iv_stopCondition & ENABLE_CMD_COMPLETE_ATTENTION_ON_CLEAN_AND_ERROR) ) + l_ecmd_rc |= l_mbasctlq.setBit(16); + + if(l_ecmd_rc) + { + l_rc.setEcmdError(l_ecmd_rc); + return l_rc; + } + + // Write stop conditions to MBASCTLQ + l_rc = fapiPutScom(iv_target, MBA01_MBASCTLQ_0x0301060F, l_mbasctlq); + if(l_rc) return l_rc; + + FAPI_INF("EXIT mss_MaintCmd::loadStopCondMask()"); + + return l_rc; +} + + +//--------------------------------------------------------- +// mss_startMaintCmd +//--------------------------------------------------------- +fapi::ReturnCode mss_MaintCmd::startMaintCmd() +{ + fapi::ReturnCode l_rc; + uint32_t l_ecmd_rc = 0; + ecmdDataBufferBase l_data(64); + + FAPI_INF("ENTER mss_MaintCmd::startMaintCmd()"); + + l_rc = fapiGetScom(iv_target, MBA01_MBMCCQ_0x0301060B, l_data); + if(l_rc) return l_rc; + + l_ecmd_rc |= l_data.setBit(0); + if(l_ecmd_rc) + { + l_rc.setEcmdError(l_ecmd_rc); + return l_rc; + } + l_rc = fapiPutScom(iv_target, MBA01_MBMCCQ_0x0301060B, l_data); + if(l_rc) return l_rc; + + FAPI_INF("EXIT mss_MaintCmd::startMaintCmd()"); + return l_rc; +} + +//--------------------------------------------------------- +// mss_postConditionCheck +//--------------------------------------------------------- +fapi::ReturnCode mss_MaintCmd::postConditionCheck() +{ + fapi::ReturnCode l_rc; + ecmdDataBufferBase l_mbmccq(64); + ecmdDataBufferBase l_mbafirq(64); + ecmdDataBufferBase l_mbmct(64); + + FAPI_INF("ENTER mss_MaintCmd::postConditionCheck()"); + + // Read MBMCCQ + l_rc = fapiGetScom(iv_target, MBA01_MBMCCQ_0x0301060B, l_mbmccq); + if(l_rc) return l_rc; + + // Read MBAFIRQ + l_rc = fapiGetScom(iv_target, MBA01_MBAFIRQ_0x03010600, l_mbafirq); + if(l_rc) return l_rc; + + // Read MBMCT[0:4], cmd type, for FFDC + l_rc = fapiGetScom(iv_target, MBA01_MBMCTQ_0x0301060A, l_mbmct); + if(l_rc) return l_rc; + + // Check for MBMCCQ[0], maint_cmd_start, to be reset by hw. + if (l_mbmccq.isBitSet(0)) + { + FAPI_ERR("MBMCCQ[0]: maint_cmd_start not reset by hw."); + + // Calling out MBA target high, deconfig, gard + const fapi::Target & MBA = iv_target; + // FFDC: Capture register we are checking + ecmdDataBufferBase & MBMCC = l_mbmccq; + // FFDC: Capture command type we are trying to run + const mss_MaintCmd::CmdType & CMD_TYPE = iv_cmdType; + // FFDC: MBMCT[0:4] contains the cmd type set in hw + ecmdDataBufferBase & MBMCT = l_mbmct; + + // Create new log + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_START_NOT_RESET); + } + + // Check for MBAFIRQ[0], invalid_maint_cmd. + if (l_mbafirq.isBitSet(0)) + { + // Log previous error before creating new log + if (l_rc) fapiLogError(l_rc); + + FAPI_ERR("MBAFIRQ[0], invalid_maint_cmd."); + + // TODO: Calling out FW high + // FFDC: MBA target + const fapi::Target & MBA = iv_target; + // FFDC: Capture register we are checking + ecmdDataBufferBase & MBAFIR = l_mbafirq; + // FFDC: Capture command type we are trying to run + const mss_MaintCmd::CmdType & CMD_TYPE = iv_cmdType; + // FFDC: MBMCT[0:4] contains the cmd type set in hw + ecmdDataBufferBase & MBMCT = l_mbmct; + + // Create new log + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_INVALID_CMD); + } + + // Check for MBAFIRQ[1], invalid_maint_address. + if (l_mbafirq.isBitSet(1)) + { + // Log previous error before creating new log + if (l_rc) fapiLogError(l_rc); + + FAPI_ERR("MBAFIRQ[1], cmd started with invalid_maint_address."); + + // TODO: Calling out FW high + // FFDC: MBA target + const fapi::Target & MBA = iv_target; + // FFDC: Capture register we are checking + ecmdDataBufferBase & MBAFIR = l_mbafirq; + // FFDC: Capture command type we are trying to run + const mss_MaintCmd::CmdType & CMD_TYPE = iv_cmdType; + // FFDC: MBMCT[0:4] contains the cmd type set in hw + ecmdDataBufferBase & MBMCT = l_mbmct; + // NOTE: List of additional FFDC regs specified in memory_errors.xml + + // Create new log + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_INVALID_ADDR); + } + + FAPI_INF("EXIT mss_MaintCmd::postConditionCheck()"); + return l_rc; +} + +//--------------------------------------------------------- +// mss_pollForMaintCmdComplete +//--------------------------------------------------------- +fapi::ReturnCode mss_MaintCmd::pollForMaintCmdComplete() +{ + + fapi::ReturnCode l_rc; + ecmdDataBufferBase l_data(64); + + FAPI_INF("ENTER mss_MaintCmd::pollForMaintCmdComplete()"); + + uint32_t count = 0; + + // 1 ms delay for HW mode + const uint64_t HW_MODE_DELAY = 100000000; + + // 200000 sim cycle delay for SIM mode + const uint64_t SIM_MODE_DELAY = 200000; + + uint32_t loop_limit = 50000; + + do + { + fapiDelay(HW_MODE_DELAY, SIM_MODE_DELAY); + + // Want to see cmd complete attention + l_rc = fapiGetScom(iv_target, MBA01_MBSPAQ_0x03010611, l_data); + if(l_rc) return l_rc; + FAPI_DBG("MBSPAQ = 0x%.8X 0x%.8X",l_data.getWord(0), l_data.getWord(1)); + + // Read MBMACAQ just to see if it's incrementing + l_rc = fapiGetScom(iv_target, MBA01_MBMACAQ_0x0301060D, l_data); + if(l_rc) return l_rc; + FAPI_DBG("MBMACAQ = 0x%.8X 0x%.8X",l_data.getWord(0), l_data.getWord(1)); + + // Waiting for MBMSRQ[0] maint cmd in progress bit to turn off + l_rc = fapiGetScom(iv_target, MBA01_MBMSRQ_0x0301060C, l_data); + if(l_rc) return l_rc; + FAPI_DBG("MBMSRQ = 0x%.8X 0x%.8X",l_data.getWord(0), l_data.getWord(1)); + + count++; + + } + // Poll until cmd in progress bit goes off + while (l_data.isBitSet(0) && (count < loop_limit)); + + if (count == loop_limit) + { + FAPI_ERR("Maint cmd timeout."); + + // TODO: Calling out FW high + // Calling out MBA target low, deconfig, gard + const fapi::Target & MBA = iv_target; + // FFDC: Capture command type we are trying to run + const mss_MaintCmd::CmdType & CMD_TYPE = iv_cmdType; + // Specify CENTAUR target so we can read some FFDC regs from MBS + const fapi::Target & CENTAUR = iv_targetCentaur; + // NOTE: List of additional FFDC regs specified in memory_errors.xml + + // Create new log + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_CMD_TIMEOUT); + } + else + { + FAPI_INF("Maint cmd complete. "); + } + + FAPI_INF("EXIT mss_MaintCmd::pollForMaintCmdComplete()"); + return l_rc; +} + +//--------------------------------------------------------- +// mss_collectFFDC +//--------------------------------------------------------- +fapi::ReturnCode mss_MaintCmd::collectFFDC() +{ + fapi::ReturnCode l_rc; + ecmdDataBufferBase l_data(64); + uint8_t l_dramSparePort0Symbol = MSS_INVALID_SYMBOL; + uint8_t l_dramSparePort1Symbol = MSS_INVALID_SYMBOL; + uint8_t l_eccSpareSymbol = MSS_INVALID_SYMBOL; + uint8_t l_symbol_mark = MSS_INVALID_SYMBOL; + uint8_t l_chip_mark = MSS_INVALID_SYMBOL; + + FAPI_INF("ENTER mss_MaintCmd::collectFFDC()"); + + l_rc = fapiGetScom(iv_target, MBA01_MBMCTQ_0x0301060A, l_data); + if(l_rc) return l_rc; + FAPI_DBG("MBMCTQ = 0x%.8X 0x%.8X", l_data.getWord(0), l_data.getWord(1)); + + l_rc = fapiGetScom(iv_target, MBA01_MBMACAQ_0x0301060D, l_data); + if(l_rc) return l_rc; + FAPI_DBG("MBMACAQ = 0x%.8X 0x%.8X", l_data.getWord(0), l_data.getWord(1)); + + // Print out error status bits from MBMACAQ + if (l_data.isBitSet(40)) FAPI_DBG("MBMACAQ error status: 40:NCE"); + if (l_data.isBitSet(41)) FAPI_DBG("MBMACAQ error status: 41:SCE"); + if (l_data.isBitSet(42)) FAPI_DBG("MBMACAQ error status: 42:MCE"); + if (l_data.isBitSet(43)) FAPI_DBG("MBMACAQ error status: 43:RCE"); + if (l_data.isBitSet(44)) FAPI_DBG("MBMACAQ error status: 44:MPE"); + if (l_data.isBitSet(45)) FAPI_DBG("MBMACAQ error status: 45:UE"); + if (l_data.isBitSet(46)) FAPI_DBG("MBMACAQ error status: 46:SUE"); + + l_rc = fapiGetScom(iv_target, MBA01_MBMEAQ_0x0301060E, l_data); + if(l_rc) return l_rc; + FAPI_DBG("MBMEAQ = 0x%.8X 0x%.8X", l_data.getWord(0), l_data.getWord(1)); + + l_rc = fapiGetScom(iv_target, MBA01_MBASCTLQ_0x0301060F, l_data); + if(l_rc) return l_rc; + FAPI_DBG("MBASCTLQ = 0x%.8X 0x%.8X", l_data.getWord(0), l_data.getWord(1)); + + l_rc = fapiGetScom(iv_target, MBA01_MBMCCQ_0x0301060B, l_data); + if(l_rc) return l_rc; + FAPI_DBG("MBMCCQ = 0x%.8X 0x%.8X", l_data.getWord(0), l_data.getWord(1)); + + l_rc = fapiGetScom(iv_target, MBA01_MBMSRQ_0x0301060C, l_data); + if(l_rc) return l_rc; + FAPI_DBG("MBMSRQ = 0x%.8X 0x%.8X", l_data.getWord(0), l_data.getWord(1)); + + l_rc = fapiGetScom(iv_target, MBA01_MBAFIRQ_0x03010600, l_data); + if(l_rc) return l_rc; + FAPI_DBG("MBAFIRQ = 0x%.8X 0x%.8X", l_data.getWord(0), l_data.getWord(1)); + + l_rc = fapiGetScom(iv_target, MBA01_MBSPAQ_0x03010611, l_data); + if(l_rc) return l_rc; + FAPI_DBG("MBSPAQ = 0x%.8X 0x%.8X", l_data.getWord(0), l_data.getWord(1)); + + l_rc = fapiGetScom(iv_target, MBA01_MBACALFIR_0x03010400, l_data); + if(l_rc) return l_rc; + FAPI_DBG("MBACALFIR = 0x%.8X 0x%.8X", l_data.getWord(0), l_data.getWord(1)); + + l_rc = fapiGetScom(iv_targetCentaur, mss_mbeccfir[iv_mbaPosition], l_data); + if(l_rc) return l_rc; + FAPI_DBG("MBECCFIR = 0x%.8X 0x%.8X", l_data.getWord(0), l_data.getWord(1)); + + // Print out maint ECC FIR bits from MBECCFIR + if (l_data.isBitSet(20)) FAPI_DBG("20:Maint MPE, rank0"); + if (l_data.isBitSet(21)) FAPI_DBG("21:Maint MPE, rank1"); + if (l_data.isBitSet(22)) FAPI_DBG("22:Maint MPE, rank2"); + if (l_data.isBitSet(23)) FAPI_DBG("23:Maint MPE, rank3"); + if (l_data.isBitSet(24)) FAPI_DBG("24:Maint MPE, rank4"); + if (l_data.isBitSet(25)) FAPI_DBG("25:Maint MPE, rank5"); + if (l_data.isBitSet(26)) FAPI_DBG("26:Maint MPE, rank6"); + if (l_data.isBitSet(27)) FAPI_DBG("27:Maint MPE, rank7"); + if (l_data.isBitSet(36)) FAPI_DBG("36: Maint NCE"); + if (l_data.isBitSet(37)) FAPI_DBG("37: Maint SCE"); + if (l_data.isBitSet(38)) FAPI_DBG("38: Maint MCE"); + if (l_data.isBitSet(39)) FAPI_DBG("39: Maint RCE"); + if (l_data.isBitSet(40)) FAPI_DBG("40: Maint SUE"); + if (l_data.isBitSet(41)) FAPI_DBG("41: Maint UE"); + + FAPI_DBG("Markstore"); + for ( uint8_t i = 0; i < MSS_MAX_RANKS; i++ ) + { + l_rc = fapiGetScom(iv_targetCentaur, mss_markStoreRegs[i][iv_mbaPosition], l_data); + if(l_rc) return l_rc; + FAPI_DBG("MBMS%d = 0x%.8X 0x%.8X",i, l_data.getWord(0), l_data.getWord(1)); + } + + for ( uint8_t i = 0; i < MSS_MAX_RANKS; i++ ) + { + l_rc = mss_get_mark_store(iv_target, i, l_symbol_mark, l_chip_mark ); + if (l_rc) + { + FAPI_ERR("Error reading markstore"); + return l_rc; + } + } + + FAPI_DBG("Steer MUXES"); + for ( uint8_t i = 0; i < MSS_MAX_RANKS; i++ ) + { + l_rc = mss_check_steering(iv_target, + i, + l_dramSparePort0Symbol, + l_dramSparePort1Symbol, + l_eccSpareSymbol); + if(l_rc) return l_rc; + } + + FAPI_INF("EXIT mss_MaintCmd::collectFFDC()"); + return l_rc; +} + + +//--------------------------------------------------------- +// mss_loadPattern +//--------------------------------------------------------- +fapi::ReturnCode mss_MaintCmd::loadPattern(PatternIndex i_initPattern) +{ + + FAPI_INF("ENTER mss_MaintCmd::loadPattern()"); + + static const uint32_t maintBufferDataRegs[2][16][2]={ + // port0 + {{MAINT0_MBS_MAINT_BUFF0_DATA0_0x0201160A, MAINT0_MBS_MAINT_BUFF0_DATA_ECC0_0x02011612}, + {MAINT0_MBS_MAINT_BUFF2_DATA0_0x0201162A, MAINT0_MBS_MAINT_BUFF2_DATA_ECC0_0x02011632}, + {MAINT0_MBS_MAINT_BUFF0_DATA1_0x0201160B, MAINT0_MBS_MAINT_BUFF0_DATA_ECC1_0x02011613}, + {MAINT0_MBS_MAINT_BUFF2_DATA1_0x0201162B, MAINT0_MBS_MAINT_BUFF2_DATA_ECC1_0x02011633}, + {MAINT0_MBS_MAINT_BUFF0_DATA2_0x0201160C, MAINT0_MBS_MAINT_BUFF0_DATA_ECC2_0x02011614}, + {MAINT0_MBS_MAINT_BUFF2_DATA2_0x0201162C, MAINT0_MBS_MAINT_BUFF2_DATA_ECC2_0x02011634}, + {MAINT0_MBS_MAINT_BUFF0_DATA3_0x0201160D, MAINT0_MBS_MAINT_BUFF0_DATA_ECC3_0x02011615}, + {MAINT0_MBS_MAINT_BUFF2_DATA3_0x0201162D, MAINT0_MBS_MAINT_BUFF2_DATA_ECC3_0x02011635}, + + // port1 + {MAINT0_MBS_MAINT_BUFF1_DATA0_0x0201161A, MAINT0_MBS_MAINT_BUFF1_DATA_ECC0_0x02011622}, + {MAINT0_MBS_MAINT_BUFF3_DATA0_0x0201163A, MAINT0_MBS_MAINT_BUFF3_DATA_ECC0_0x02011642}, + {MAINT0_MBS_MAINT_BUFF1_DATA1_0x0201161B, MAINT0_MBS_MAINT_BUFF1_DATA_ECC1_0x02011623}, + {MAINT0_MBS_MAINT_BUFF3_DATA1_0x0201163B, MAINT0_MBS_MAINT_BUFF3_DATA_ECC1_0x02011643}, + {MAINT0_MBS_MAINT_BUFF1_DATA2_0x0201161C, MAINT0_MBS_MAINT_BUFF1_DATA_ECC2_0x02011624}, + {MAINT0_MBS_MAINT_BUFF3_DATA2_0x0201163C, MAINT0_MBS_MAINT_BUFF3_DATA_ECC2_0x02011644}, + {MAINT0_MBS_MAINT_BUFF1_DATA3_0x0201161D, MAINT0_MBS_MAINT_BUFF1_DATA_ECC3_0x02011625}, + {MAINT0_MBS_MAINT_BUFF3_DATA3_0x0201163D, MAINT0_MBS_MAINT_BUFF3_DATA_ECC3_0x02011645}}, + + // port2 + {{MAINT1_MBS_MAINT_BUFF0_DATA0_0x0201170A, MAINT1_MBS_MAINT_BUFF0_DATA_ECC0_0x02011712}, + {MAINT1_MBS_MAINT_BUFF2_DATA0_0x0201172A, MAINT1_MBS_MAINT_BUFF2_DATA_ECC0_0x02011732}, + {MAINT1_MBS_MAINT_BUFF0_DATA1_0x0201170B, MAINT1_MBS_MAINT_BUFF0_DATA_ECC1_0x02011713}, + {MAINT1_MBS_MAINT_BUFF2_DATA1_0x0201172B, MAINT1_MBS_MAINT_BUFF2_DATA_ECC1_0x02011733}, + {MAINT1_MBS_MAINT_BUFF0_DATA2_0x0201170C, MAINT1_MBS_MAINT_BUFF0_DATA_ECC2_0x02011714}, + {MAINT1_MBS_MAINT_BUFF2_DATA2_0x0201172C, MAINT1_MBS_MAINT_BUFF2_DATA_ECC2_0x02011734}, + {MAINT1_MBS_MAINT_BUFF0_DATA3_0x0201170D, MAINT1_MBS_MAINT_BUFF0_DATA_ECC3_0x02011715}, + {MAINT1_MBS_MAINT_BUFF2_DATA3_0x0201172D, MAINT1_MBS_MAINT_BUFF2_DATA_ECC3_0x02011735}, + + // port3 + {MAINT1_MBS_MAINT_BUFF1_DATA0_0x0201171A, MAINT1_MBS_MAINT_BUFF1_DATA_ECC0_0x02011722}, + {MAINT1_MBS_MAINT_BUFF3_DATA0_0x0201173A, MAINT1_MBS_MAINT_BUFF3_DATA_ECC0_0x02011742}, + {MAINT1_MBS_MAINT_BUFF1_DATA1_0x0201171B, MAINT1_MBS_MAINT_BUFF1_DATA_ECC1_0x02011723}, + {MAINT1_MBS_MAINT_BUFF3_DATA1_0x0201173B, MAINT1_MBS_MAINT_BUFF3_DATA_ECC1_0x02011743}, + {MAINT1_MBS_MAINT_BUFF1_DATA2_0x0201171C, MAINT1_MBS_MAINT_BUFF1_DATA_ECC2_0x02011724}, + {MAINT1_MBS_MAINT_BUFF3_DATA2_0x0201173C, MAINT1_MBS_MAINT_BUFF3_DATA_ECC2_0x02011744}, + {MAINT1_MBS_MAINT_BUFF1_DATA3_0x0201171D, MAINT1_MBS_MAINT_BUFF1_DATA_ECC3_0x02011725}, + {MAINT1_MBS_MAINT_BUFF3_DATA3_0x0201173D, MAINT1_MBS_MAINT_BUFF3_DATA_ECC3_0x02011745}}}; + + + static const uint32_t maintBuffer65thRegs[4][2]={ + {MAINT0_MBS_MAINT_BUFF_65TH_BYTE_64B_ECC0_0x0201164A, MAINT1_MBS_MAINT_BUFF_65TH_BYTE_64B_ECC0_0x0201174A}, + {MAINT0_MBS_MAINT_BUFF_65TH_BYTE_64B_ECC1_0x0201164B, MAINT1_MBS_MAINT_BUFF_65TH_BYTE_64B_ECC1_0x0201174B}, + {MAINT0_MBS_MAINT_BUFF_65TH_BYTE_64B_ECC2_0x0201164C, MAINT1_MBS_MAINT_BUFF_65TH_BYTE_64B_ECC2_0x0201174C}, + {MAINT0_MBS_MAINT_BUFF_65TH_BYTE_64B_ECC3_0x0201164D, MAINT1_MBS_MAINT_BUFF_65TH_BYTE_64B_ECC3_0x0201174D}}; + + + fapi::ReturnCode l_rc; + uint32_t l_ecmd_rc = 0; + ecmdDataBufferBase l_data(64); + ecmdDataBufferBase l_ecc(64); + ecmdDataBufferBase l_65th(64); + ecmdDataBufferBase l_mbmmr(64); + ecmdDataBufferBase l_mbsecc(64); + uint32_t loop = 0; + + FAPI_INF("pattern = 0x%.8X 0x%.8X", + mss_maintBufferData[i_initPattern][0][0], + mss_maintBufferData[i_initPattern][0][1]); + + //---------------------------------------------------- + // Load the data: 16 loops x 64bits = 128B cacheline + //---------------------------------------------------- + FAPI_INF("Load the data: 16 loops x 64bits = 128B cacheline"); + + // Set bit 9 so that hw will generate the fabric ECC. + // This is an 8B ECC protecting the data moving on internal buses in + // the Centaur. + l_ecmd_rc |= l_ecc.flushTo0(); + l_ecmd_rc |= l_ecc.setBit(9); + if(l_ecmd_rc) + { + l_rc.setEcmdError(l_ecmd_rc); + return l_rc; + } + + for(loop=0; loop<16; loop++ ) + { + // A write to MAINT_BUFFx_DATAy will not update until the corresponding + // MAINT_BUFFx_DATA_ECCy is written to. + l_ecmd_rc |= l_data.insert(mss_maintBufferData[i_initPattern][loop][0], 0, 32, 0); + l_ecmd_rc |= l_data.insert(mss_maintBufferData[i_initPattern][loop][1], 32, 32, 0); + if(l_ecmd_rc) + { + l_rc.setEcmdError(l_ecmd_rc); + return l_rc; + } + l_rc = fapiPutScom(iv_targetCentaur, maintBufferDataRegs[iv_mbaPosition][loop][0], l_data); + if(l_rc) return l_rc; + + l_rc = fapiPutScom(iv_targetCentaur, maintBufferDataRegs[iv_mbaPosition][loop][1], l_ecc); + if(l_rc) return l_rc; + } + + //---------------------------------------------------- + // Load the 65th byte: 4 loops to fill in the two 65th bytes in cacheline + //---------------------------------------------------- + FAPI_INF("Load the 65th byte: 4 loops to fill in the two 65th bytes in the cacheline"); + + l_ecmd_rc |= l_65th.flushTo0(); + + // Set bit 56 so that hw will generate the fabric ECC. + // This is an 8B ECC protecting the data moving on internal buses in Centaur. + l_ecmd_rc |= l_65th.setBit(56); + if(l_ecmd_rc) + { + l_rc.setEcmdError(l_ecmd_rc); + return l_rc; + } + + for(loop=0; loop<4; loop++ ) + { + l_ecmd_rc |= l_65th.insert(mss_65thByte[i_initPattern][loop], 1, 3, 1); + if(l_ecmd_rc) + { + l_rc.setEcmdError(l_ecmd_rc); + return l_rc; + } + + l_rc = fapiPutScom(iv_targetCentaur, maintBuffer65thRegs[loop][iv_mbaPosition], l_65th); + if(l_rc) return l_rc; + } + + //---------------------------------------------------- + // Save i_initPattern in unused maint mark reg + // so we know what pattern was used when we do + // UE isolation + //---------------------------------------------------- + + // No plans to use maint mark, but make sure it's disabled to be safe + l_rc = fapiGetScom(iv_targetCentaur, mss_mbsecc[iv_mbaPosition], l_mbsecc); + if(l_rc) return l_rc; + l_ecmd_rc |= l_mbsecc.clearBit(4); + if(l_ecmd_rc) + { + l_rc.setEcmdError(l_ecmd_rc); + return l_rc; + } + l_rc = fapiPutScom(iv_targetCentaur, mss_mbsecc[iv_mbaPosition], l_mbsecc); + if(l_rc) return l_rc; + + + l_ecmd_rc |= l_mbmmr.flushTo0(); + // Store i_initPattern, with range 0-8, in MBMMR bits 4-7 + l_ecmd_rc |= l_mbmmr.insert((uint8_t)i_initPattern, 4, 4, 8-4); + if(l_ecmd_rc) + { + l_rc.setEcmdError(l_ecmd_rc); + return l_rc; + } + l_rc = fapiPutScom(iv_targetCentaur, mss_mbmmr[iv_mbaPosition] , l_mbmmr); + if(l_rc) return l_rc; + + + + + FAPI_INF("EXIT mss_MaintCmd::loadPattern()"); + + return l_rc; +} + +//--------------------------------------------------------- +// mss_loadSpeed +//--------------------------------------------------------- +fapi::ReturnCode mss_MaintCmd::loadSpeed(TimeBaseSpeed i_speed) +{ + + FAPI_INF("ENTER mss_MaintCmd::loadSpeed()"); + + fapi::ReturnCode l_rc; + uint32_t l_ecmd_rc = 0; + ecmdDataBufferBase l_data(64); + uint32_t l_ddr_freq = 0; + uint64_t l_step_size = 0; + uint64_t l_num_address_bits = 0; + uint64_t l_num_addresses = 0; + uint64_t l_address_bit = 0; + ecmdDataBufferBase l_start_address(64); + ecmdDataBufferBase l_end_address(64); + uint64_t l_cmd_interval = 0; + + // burst_window_sel + // MBMCTQ[6]: 0 = 512 Maint Clks + // 1 = 536870912 Maint Clks + uint8_t l_burst_window_sel = 0; + + // timebase_sel + // MBMCTQ[9:10]: 00 = 1 Maint Clk + // 01 = 8192 Maint clks + uint8_t l_timebase_sel = 0; + + // timebase_burst_sel + // MBMCTQ[11]: 0 = disable burst mode + // 1 = enable burst mode + uint8_t l_timebase_burst_sel = 0; + + // timebase_interval + // MBMCTQ[12:23]: The operation interval for timebase operations + // equals the timebase_sel x MBMCTQ[12:23]. + // NOTE: Should never be 0, or will hang mainline traffic. + uint32_t l_timebase_interval = 1; + + // burst_window + // MBMCTQ[24:31]: The burst window for timebase operations with burst mode + // enabled equals burst_window_sel x MBMCTQ[24:31] + uint8_t l_burst_window = 0; + + // burst_interval + // MBMCTQ[32:39]: The burst interval for timebase operations with burst mode + // enabled equals the number of burst windows that will have + // no operations occurring in them. + uint8_t l_burst_interval = 0; + + l_rc = fapiGetScom(iv_target, MBA01_MBMCTQ_0x0301060A, l_data); + if(l_rc) return l_rc; + + + // FAST_AS_POSSIBLE + if (i_speed == FAST_AS_POSSIBLE) + { + // TODO: Need to figure out what fastest possible setting is. + l_burst_window_sel = 0; + l_timebase_sel = 0; + l_timebase_burst_sel = 0; + l_timebase_interval = 32; + l_burst_window = 0; + l_burst_interval = 0; + } + // SLOW_12H + else + { + // Get l_ddr_freq from ATTR_MSS_FREQ + // Possible frequencies are 800, 1066, 1333, 1600, 1866, and 2133 MHz + // NOTE: Max 32 address bits using 800 and 1066 result in scrub + // taking longer than 12h, but these is no plan to actually use + // those frequencies. + l_rc = FAPI_ATTR_GET( ATTR_MSS_FREQ, &iv_targetCentaur, l_ddr_freq); + if (l_rc) + { + FAPI_ERR("Failed to get attribute: ATTR_MSS_FREQ."); + return l_rc; + } + + // Make sure it's non-zero, to avoid divide by 0 + if (l_ddr_freq == 0) + { + FAPI_ERR("ATTR_MSS_FREQ set to zero so can't calculate scrub rate."); + + // TODO: Calling out FW high + // FFDC: MBA target + const fapi::Target & MBA = iv_target; + // FFDC: Capture l_ddr_freq + uint32_t DDR_FREQ = l_ddr_freq; + // FFDC: Capture command type we are trying to run + const mss_MaintCmd::CmdType & CMD_TYPE = iv_cmdType; + + // Create new log + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_ZERO_DDR_FREQ); + return l_rc; + } + + // l_timebase_sel + // MBMCTQ[9:10]: 00 = 1 * Maint Clk + // 01 = 8192 * Maint Clk + // Where Maint Clk = 2/1_ddr_freq + l_timebase_sel = 1; + + // Get l_step_size in nSec + l_step_size = 8192*2*1000/l_ddr_freq; + + FAPI_DBG("l_ddr_freq = %d MHz, l_step_size = %d nSec", + (uint32_t)l_ddr_freq, (uint32_t)l_step_size); + + // Get l_end_address + l_rc = mss_get_address_range( iv_target, + MSS_ALL_RANKS, + l_start_address, + l_end_address ); + if (l_rc) + { + FAPI_ERR("mss_get_address_range failed. "); + return l_rc; + } + + // Get l_num_address_bits by counting bits set to 1 in l_end_address. + for(l_address_bit=0; l_address_bit<37; l_address_bit++ ) + { + if(l_end_address.isBitSet(l_address_bit)) + { + l_num_address_bits++; + } + } + + // NOTE: Assumption is max 32 address bits, which can be done + // in 12h (+/- 2h). More than 32 address bits would + // double scrub time for every extra address bit. + if (l_num_address_bits > 32) + { + FAPI_INF("WARNING: l_num_address_bits: %d, is greater than 32, so scrub will take longer than 12h.",(uint32_t)l_num_address_bits); + } + + // NOTE: Smallest number of address bits is supposed to be 25. + // So if for some reason it's less (like in VBU), + // use 25 anyway so the scrub rate calculation still works. + if (l_num_address_bits < 25) + { + FAPI_INF("WARNING: l_num_address_bits: %d, is less than 25, but using 25 in calculation anyway.",(uint32_t)l_num_address_bits); + l_num_address_bits = 25; + } + + // Get l_num_addresses + l_num_addresses = 1; + for(uint32_t i=0; i<l_num_address_bits; i++ ) + { + l_num_addresses *=2; + } + // Convert to M addresses + l_num_addresses /=1000000; + + // Get interval between cmds in order to through l_num_addresses in 12h + l_cmd_interval = (12 * 60 * 60 * 1000)/l_num_addresses; + + // How many times to multiply l_step_size to get l_cmd_interval? + l_timebase_interval = l_cmd_interval/l_step_size; + + // Round up to nearest integer for more accurate number + l_timebase_interval += (l_cmd_interval % l_step_size >= l_step_size/2) ? 1:0; + + // Make sure smallest is 1 + if (l_timebase_interval == 0) l_timebase_interval = 1; + + FAPI_DBG("l_num_address_bits = %d, l_num_addresses = %d (M), l_cmd_interval = %d nSec, l_timebase_interval = %d", + (uint32_t)l_num_address_bits, (uint32_t)l_num_addresses, (uint32_t)l_cmd_interval, (uint32_t)l_timebase_interval); + + // Disable burst mode + l_timebase_burst_sel = 0; // Disable burst mode + l_burst_window_sel = 0; // Don't care since burst mode disabled + l_burst_window = 0; // Don't care since burst mode disabled + l_burst_interval = 0; // Don't care since burst mode disabled + + return l_rc; + + } + + + // burst_window_sel + // MBMCTQ[6] + l_ecmd_rc |= l_data.insert( l_burst_window_sel, 6, 1, 8-1 ); + + // timebase_sel + // MBMCTQ[9:10] + l_ecmd_rc |= l_data.insert( l_timebase_sel, 9, 2, 8-2 ); + + // timebase_burst_sel + // MBMCTQ[11] + l_ecmd_rc |= l_data.insert( l_timebase_burst_sel, 11, 1, 8-1 ); + + // timebase_interval + // MBMCTQ[12:23] + l_ecmd_rc |= l_data.insert( l_timebase_interval, 12, 12, 32-12 ); + + // burst_window + // MBMCTQ[24:31] + l_ecmd_rc |= l_data.insert( l_burst_window, 24, 8, 8-8 ); + + // burst_interval + // MBMCTQ[32:39] + l_ecmd_rc |= l_data.insert( l_burst_interval, 32, 8, 8-8 ); + + if(l_ecmd_rc) + { + l_rc.setEcmdError(l_ecmd_rc); + return l_rc; + } + + l_rc = fapiPutScom(iv_target, MBA01_MBMCTQ_0x0301060A, l_data); + if(l_rc) return l_rc; + + FAPI_INF("EXIT mss_MaintCmd::loadSpeed()"); + + return l_rc; +} + + + + + + + +//------------------------------------------------------------------------------ +// Child classes +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +// SuperFastInit +//------------------------------------------------------------------------------ + + +const mss_MaintCmd::CmdType mss_SuperFastInit::cv_cmdType = SUPERFAST_INIT; + +//--------------------------------------------------------- +// mss_SuperFastInit Constructor +//--------------------------------------------------------- +mss_SuperFastInit::mss_SuperFastInit( const fapi::Target & i_target, + const ecmdDataBufferBase & i_startAddr, + const ecmdDataBufferBase & i_endAddr, + PatternIndex i_initPattern, + uint32_t i_stopCondition, + bool i_poll ) : + mss_MaintCmd( i_target, + i_startAddr, + i_endAddr, + i_stopCondition, + i_poll, + cv_cmdType), + iv_initPattern( i_initPattern ) // NOTE: iv_initPattern is instance + // variable of SuperFastInit, since not + // needed in parent class + {} + + + + + +//--------------------------------------------------------- +// mss_SuperFastInit setupAndExecuteCmd +//--------------------------------------------------------- +fapi::ReturnCode mss_SuperFastInit::setupAndExecuteCmd() +{ + + + FAPI_INF("ENTER mss_SuperFastInit::setupAndExecuteCmd()"); + + + fapi::ReturnCode l_rc; + ecmdDataBufferBase l_data(64); + + // Gather data that needs to be stored. For testing purposes we will just + // set an abitrary number. + //l_rc = setSavedData( 0xdeadbeef ); if(l_rc) return l_rc; + //printf( "Saved data: 0x%08x\n", getSavedData() ); + + + // Make sure maint logic in valid state to run new cmd + l_rc = preConditionCheck(); if(l_rc) return l_rc; + + // Load pattern + l_rc = loadPattern(iv_initPattern); if(l_rc) return l_rc; + + // Load cmd type: MBMCTQ + l_rc = loadCmdType(); if(l_rc) return l_rc; + + // Load start address: MBMACAQ + l_rc = loadStartAddress(); if(l_rc) return l_rc; + + // Load end address: MBMEAQ + l_rc = loadEndAddress(); if(l_rc) return l_rc; + + + // Load stop conditions: MBASCTLQ + l_rc = loadStopCondMask(); if(l_rc) return l_rc; + + // Start the command: MBMCCQ + l_rc = startMaintCmd(); if(l_rc) return l_rc; + + // Check for early problems with maint cmd instead of waiting for + // cmd timeout + l_rc = postConditionCheck(); if(l_rc) return l_rc; + + if(iv_poll == false) + { + FAPI_INF("Cmd has started. Use attentions to detect cmd complete."); + return l_rc; + } + + // Poll for command complete: MBMSRQ + l_rc = pollForMaintCmdComplete(); if(l_rc) return l_rc; + + // Collect FFDC + l_rc = collectFFDC(); if(l_rc) return l_rc; + + FAPI_INF("EXIT mss_SuperFastInit::setupAndExecuteCmd()"); + + return l_rc; +} + + + + +//------------------------------------------------------------------------------ +// mss_SuperFastRandomInit +//------------------------------------------------------------------------------ + + +const mss_MaintCmd::CmdType mss_SuperFastRandomInit::cv_cmdType = SUPERFAST_RANDOM_INIT; + +//--------------------------------------------------------- +// mss_SuperFastInit Constructor +//--------------------------------------------------------- +mss_SuperFastRandomInit::mss_SuperFastRandomInit( const fapi::Target & i_target, + const ecmdDataBufferBase & i_startAddr, + const ecmdDataBufferBase & i_endAddr, + PatternIndex i_initPattern, + uint32_t i_stopCondition, + bool i_poll ) : + mss_MaintCmd( i_target, + i_startAddr, + i_endAddr, + i_stopCondition, + i_poll, + cv_cmdType), + iv_initPattern( i_initPattern ) + {} + + + + + +//--------------------------------------------------------- +// mss_SuperFastRandomInit setupAndExecuteCmd +//--------------------------------------------------------- +fapi::ReturnCode mss_SuperFastRandomInit::setupAndExecuteCmd() +{ + + + FAPI_INF("ENTER mss_SuperFastRandomInit::setupAndExecuteCmd()"); + + + fapi::ReturnCode l_rc; + uint32_t l_ecmd_rc = 0; + + // Gather data that needs to be stored. For testing purposes we will just + // set an abitrary number. + //l_rc = setSavedData( 0xdeadbeef ); if(l_rc) return l_rc; + //printf( "Saved data: 0x%08x\n", getSavedData() ); + + + // Make sure maint logic in valid state to run new cmd + l_rc = preConditionCheck(); if(l_rc) return l_rc; + + // Load pattern + l_rc = loadPattern(iv_initPattern); if(l_rc) return l_rc; + + // Load cmd type: MBMCTQ + l_rc = loadCmdType(); if(l_rc) return l_rc; + + // Load start address: MBMACAQ + l_rc = loadStartAddress(); if(l_rc) return l_rc; + + // Load end address: MBMEAQ + l_rc = loadEndAddress(); if(l_rc) return l_rc; + + // Load stop conditions: MBASCTLQ + l_rc = loadStopCondMask(); if(l_rc) return l_rc; + + // Disable 8B ECC check/correct on WRD data bus: MBA_WRD_MODE(0:1) = 11 + // before a SuperFastRandomInit command is issued + l_rc = fapiGetScom(iv_target, MBA01_MBA_WRD_MODE_0x03010449, iv_saved_MBA_WRD_MODE); + if(l_rc) return l_rc; + + ecmdDataBufferBase l_data(64); + l_ecmd_rc |= l_data.insert(iv_saved_MBA_WRD_MODE, 0, 64, 0); + l_ecmd_rc |= l_data.setBit(0); + l_ecmd_rc |= l_data.setBit(1); + if(l_ecmd_rc) + { + l_rc.setEcmdError(l_ecmd_rc); + return l_rc; + } + l_rc = fapiPutScom(iv_target, MBA01_MBA_WRD_MODE_0x03010449, l_data); + if(l_rc) return l_rc; + + // Start the command: MBMCCQ + l_rc = startMaintCmd(); if(l_rc) return l_rc; + + // Check for early problems with maint cmd instead of waiting for + //cmd timeout + l_rc = postConditionCheck(); if(l_rc) return l_rc; + + if(iv_poll == false) + { + FAPI_INF("Cmd has started. Use attentions to detect cmd complete."); + return l_rc; + } + + // Poll for command complete: MBMSRQ + l_rc = pollForMaintCmdComplete(); if(l_rc) return l_rc; + + // Collect FFDC + l_rc = collectFFDC(); if(l_rc) return l_rc; + + FAPI_INF("EXIT mss_SuperFastRandomInit::setupAndExecuteCmd()"); + + return l_rc; +} + + +fapi::ReturnCode mss_SuperFastRandomInit::cleanupCmd() +{ + + FAPI_INF("ENTER mss_SuperFastRandomInit::cleanupCmd()"); + + fapi::ReturnCode l_rc; + + // Clear maintenance command complete attention, scrub stats, etc... + + // Restore MBA_WRD_MODE + l_rc = fapiPutScom(iv_target, MBA01_MBA_WRD_MODE_0x03010449, iv_saved_MBA_WRD_MODE); + if(l_rc) return l_rc; + + FAPI_INF("EXIT mss_SuperFastRandomInit::cleanupCmd()"); + + return l_rc; +} + + + +//------------------------------------------------------------------------------ +// mss_SuperFastRead +//------------------------------------------------------------------------------ + +const mss_MaintCmd::CmdType mss_SuperFastRead::cv_cmdType = SUPERFAST_READ; + +//--------------------------------------------------------- +// mss_SuperFastRead Constructor +//--------------------------------------------------------- + +mss_SuperFastRead::mss_SuperFastRead( const fapi::Target & i_target, + const ecmdDataBufferBase & i_startAddr, + const ecmdDataBufferBase & i_endAddr, + uint32_t i_stopCondition, + bool i_poll ) : + mss_MaintCmd( i_target, + i_startAddr, + i_endAddr, + i_stopCondition, + i_poll, + cv_cmdType){} + +//--------------------------------------------------------- +// mss_SuperReadInit setupAndExecuteCmd +//--------------------------------------------------------- + +fapi::ReturnCode mss_SuperFastRead::setupAndExecuteCmd() +{ + FAPI_INF("ENTER mss_SuperFastRead::setupAndExecuteCmd()"); + + fapi::ReturnCode l_rc; + uint32_t l_ecmd_rc = 0; + + // Gather data that needs to be stored. For testing purposes we will just + // set an abitrary number. + //l_rc = setSavedData( 0xdeadbeef ); if(l_rc) return l_rc; + //printf( "Saved data: 0x%08x\n", getSavedData() ); + + // Make sure maint logic in valid state to run new cmd + l_rc = preConditionCheck(); if(l_rc) return l_rc; + + // Setup required to trap UE actual data needed for IPL UE isolation + l_rc = ueTrappingSetup(); if(l_rc) return l_rc; + + // Load cmd type: MBMCTQ + l_rc = loadCmdType(); if(l_rc) return l_rc; + + // Load start address: MBMACAQ + l_rc = loadStartAddress(); if(l_rc) return l_rc; + + // Load end address: MBMEAQ + l_rc = loadEndAddress(); if(l_rc) return l_rc; + + // Load stop conditions: MBASCTLQ + l_rc = loadStopCondMask(); if(l_rc) return l_rc; + + // Need to set RRQ to fifo mode to ensure super fast read commands + // are done on order. Otherwise, if cmds get out of order we can't be sure + // the trapped address in MBMACA will be correct when we stop + // on error. That means we could unintentionally skip addresses if we just + // try to increment MBMACA and continue. + // NOTE: Cleanup needs to be done to restore settings done. + l_rc = fapiGetScom(iv_target, MBA01_MBA_RRQ0Q_0x0301040E, iv_saved_MBA_RRQ0); + if(l_rc) return l_rc; + + ecmdDataBufferBase l_data(64); + l_ecmd_rc |= l_data.insert(iv_saved_MBA_RRQ0, 0, 64, 0); + l_ecmd_rc |= l_data.clearBit(6,5); // Set 6:10 = 00000 (fifo mode) + l_ecmd_rc |= l_data.setBit(12); // Disable MBA RRQ fastpath + if(l_ecmd_rc) + { + l_rc.setEcmdError(l_ecmd_rc); + return l_rc; + } + l_rc = fapiPutScom(iv_target, MBA01_MBA_RRQ0Q_0x0301040E, l_data); + if(l_rc) return l_rc; + + + + /* + // DEBUG. Set hard CE threshold to 1: MBSTRQ + FAPI_INF("\nDEBUG. Set hard CE threshold to 1: MBSTRQ"); + ecmdDataBufferBase l_data(64); + uint32_t l_hardCEThreshold = 1; + l_rc = fapiGetScom(iv_target, MBS01_MBSTRQ_0x02011655, l_data); + if(l_rc) return l_rc; + l_data.insert( l_hardCEThreshold, 28, 12, 32-12 ); // 28:39 hard ce threshold + l_data.setBit(2); // Enable hard ce ETE special attention + l_data.setBit(57); // Enable per-symbol counters to count hard ces + l_rc = fapiPutScom(iv_target, MBS01_MBSTRQ_0x02011655, l_data); + if(l_rc) return l_rc; + */ + + // Start the command: MBMCCQ + l_rc = startMaintCmd(); if(l_rc) return l_rc; + + // Check for early problems with maint cmd instead of waiting for + // cmd timeout + l_rc = postConditionCheck(); if(l_rc) return l_rc; + + if(iv_poll == false) + { + FAPI_INF("Cmd has started. Use attentions to detect cmd complete."); + return l_rc; + } + + // Poll for command complete: MBMSRQ + l_rc = pollForMaintCmdComplete(); if(l_rc) return l_rc; + + // Collect FFDC + l_rc = collectFFDC(); if(l_rc) return l_rc; + + FAPI_INF("EXIT mss_SuperFastRead::setupAndExecuteCmd()"); + + return l_rc; + +} + +fapi::ReturnCode mss_SuperFastRead::ueTrappingSetup() +{ + + FAPI_INF("ENTER mss_SuperFastRead::ueTrappingSetup()"); + + fapi::ReturnCode l_rc; + + static const uint32_t maintBufferDataRegs[2][2][2]={ + // port0/1 + {{MAINT0_MBS_MAINT_BUFF0_DATA0_0x0201160A, MAINT0_MBS_MAINT_BUFF0_DATA_ECC0_0x02011612}, + {MAINT0_MBS_MAINT_BUFF0_DATA4_0x0201160E, MAINT0_MBS_MAINT_BUFF0_DATA_ECC4_0x02011616}}, + // port2/3 + {{MAINT1_MBS_MAINT_BUFF0_DATA0_0x0201170A, MAINT1_MBS_MAINT_BUFF0_DATA_ECC0_0x02011712}, + {MAINT1_MBS_MAINT_BUFF0_DATA4_0x0201170E, MAINT1_MBS_MAINT_BUFF0_DATA_ECC4_0x02011716}}}; + + uint32_t l_ecmd_rc = 0; + ecmdDataBufferBase l_data(64); + ecmdDataBufferBase l_ecc(64); + ecmdDataBufferBase l_mbstr(64); + uint32_t loop = 0; + + // Set bit 9 so that hw will generate the fabric ECC. + // This is an 8B ECC protecting the data moving on internal buses in + // the Centaur. + l_ecmd_rc |= l_ecc.flushTo0(); + l_ecmd_rc |= l_ecc.setBit(9); + + + for(loop=0; loop<2; loop++ ) + { + // Load unique pattern into both halves of the maint buffer, + // so we can tell which half contains a trapped UE. + l_ecmd_rc |= l_data.insert(0xFACEB00C, 0, 32, 0); + l_ecmd_rc |= l_data.insert(0xD15C0DAD, 32, 32, 0); + if(l_ecmd_rc) + { + l_rc.setEcmdError(l_ecmd_rc); + return l_rc; + } + l_rc = fapiPutScom(iv_targetCentaur, maintBufferDataRegs[iv_mbaPosition][loop][0], l_data); + if(l_rc) return l_rc; + + // A write to MAINT_BUFFx_DATAy will not update until the corresponding + // MAINT_BUFFx_DATA_ECCy is written to. + l_rc = fapiPutScom(iv_targetCentaur, maintBufferDataRegs[iv_mbaPosition][loop][1], l_ecc); + if(l_rc) return l_rc; + } + + + // Enable UE trapping + l_rc = fapiGetScom(iv_targetCentaur, mss_mbstr[iv_mbaPosition], l_mbstr); + if(l_rc) return l_rc; + l_mbstr.setBit(59); + l_rc = fapiPutScom(iv_targetCentaur, mss_mbstr[iv_mbaPosition], l_mbstr); + if(l_rc) return l_rc; + + + FAPI_INF("EXIT mss_SuperFastRead::ueTrappingSetup()"); + + return l_rc; +} + + +fapi::ReturnCode mss_SuperFastRead::cleanupCmd() +{ + + FAPI_INF("ENTER mss_SuperFastRead::cleanupCmd()"); + + fapi::ReturnCode l_rc; + ecmdDataBufferBase l_mbstr(64); + + // Clear maintenance command complete attention, scrub stats, etc... + + // Restore the saved data. + //printf( "Saved data: 0x%08x\n", getSavedData() ); + + // Undo rrq fifo mode + l_rc = fapiPutScom(iv_target, MBA01_MBA_RRQ0Q_0x0301040E, iv_saved_MBA_RRQ0); + if(l_rc) return l_rc; + + // Disable UE trapping + l_rc = fapiGetScom(iv_targetCentaur, mss_mbstr[iv_mbaPosition], l_mbstr); + if(l_rc) return l_rc; + l_mbstr.clearBit(59); + l_rc = fapiPutScom(iv_targetCentaur, mss_mbstr[iv_mbaPosition], l_mbstr); + if(l_rc) return l_rc; + + + FAPI_INF("EXIT mss_SuperFastRead::cleanupCmd()"); + + return l_rc; +} + + + +//------------------------------------------------------------------------------ +// AtomicInject +//------------------------------------------------------------------------------ + +const mss_MaintCmd::CmdType mss_AtomicInject::cv_cmdType = ATOMIC_ALTER_ERROR_INJECT; + +//--------------------------------------------------------- +// AtomicInject Constructor +//--------------------------------------------------------- + +mss_AtomicInject::mss_AtomicInject( const fapi::Target & i_target, + const ecmdDataBufferBase & i_startAddr, + InjectType i_injectType ) : + mss_MaintCmd( i_target, + i_startAddr, + ecmdDataBufferBase(64), // i_endAddr not used for this cmd + NO_STOP_CONDITIONS, // i_stopCondition not used for this cmd + true, // i_poll always true for this cmd + cv_cmdType), + + iv_injectType( i_injectType ) // NOTE: iv_injectType is instance variable + // of AtomicInject, since not needed + // in parent class + {} + + +//--------------------------------------------------------- +// mss_AtomicInject setupAndExecuteCmd +//--------------------------------------------------------- + +fapi::ReturnCode mss_AtomicInject::setupAndExecuteCmd() +{ + FAPI_INF("ENTER mss_AtomicInject::setupAndExecuteCmd()"); + + fapi::ReturnCode l_rc; + uint32_t l_ecmd_rc = 0; + + // Gather data that needs to be stored. For testing purposes we will just + // set an abitrary number. + //l_rc = setSavedData( 0xdeadbeef ); if(l_rc) return l_rc; + //printf( "Saved data: 0x%08x\n", getSavedData() ); + + // Make sure maint logic in valid state to run new cmd + l_rc = preConditionCheck(); if(l_rc) return l_rc; + + // Load cmd type: MBMCTQ + l_rc = loadCmdType(); if(l_rc) return l_rc; + + // Load start address: MBMACAQ + l_rc = loadStartAddress(); if(l_rc) return l_rc; + + // Load stop conditions: MBASCTLQ + l_rc = loadStopCondMask(); if(l_rc) return l_rc; + + // Load inject type: MBECTLQ + ecmdDataBufferBase l_injectType(64); + l_rc = fapiGetScom(iv_target, MBA01_MBECTLQ_0x03010610, l_injectType); + if(l_rc) return l_rc; + l_ecmd_rc |= l_injectType.flushTo0(); + l_ecmd_rc |= l_injectType.setBit(iv_injectType); + if(l_ecmd_rc) + { + l_rc.setEcmdError(l_ecmd_rc); + return l_rc; + } + l_rc = fapiPutScom(iv_target, MBA01_MBECTLQ_0x03010610, l_injectType); + if(l_rc) return l_rc; + + // Start the command: MBMCCQ + l_rc = startMaintCmd(); if(l_rc) return l_rc; + + // Check for early problems with maint cmd instead of waiting for + // cmd timeout + l_rc = postConditionCheck(); if(l_rc) return l_rc; + + // Poll for command complete: MBMSRQ + l_rc = pollForMaintCmdComplete(); if(l_rc) return l_rc; + + // Collect FFDC + l_rc = collectFFDC(); if(l_rc) return l_rc; + + // Clear MBECCFIR + ecmdDataBufferBase l_data(64); + l_ecmd_rc |= l_data.flushTo0(); + if(l_ecmd_rc) + { + l_rc.setEcmdError(l_ecmd_rc); + return l_rc; + } + + l_rc = fapiPutScom(iv_targetCentaur, mss_mbeccfir[iv_mbaPosition], l_data); + if(l_rc) return l_rc; + + FAPI_INF("EXIT mss_AtomicInject::setupAndExecuteCmd()"); + + + return l_rc; + +} + + +//------------------------------------------------------------------------------ +// Display +//------------------------------------------------------------------------------ + +const mss_MaintCmd::CmdType mss_Display::cv_cmdType = MEMORY_DISPLAY; + +//--------------------------------------------------------- +// Display Constructor +//--------------------------------------------------------- + +mss_Display::mss_Display( const fapi::Target & i_target, + const ecmdDataBufferBase & i_startAddr) : + mss_MaintCmd( i_target, + i_startAddr, + ecmdDataBufferBase(64), // i_endAddr not used for this cmd + NO_STOP_CONDITIONS, // i_stopCondition not used for this cmd + true, // i_poll always true for this cmd + cv_cmdType){} + + +//--------------------------------------------------------- +// mss_Display setupAndExecuteCmd +//--------------------------------------------------------- + +fapi::ReturnCode mss_Display::setupAndExecuteCmd() +{ + FAPI_INF("ENTER mss_Display::setupAndExecuteCmd()"); + + fapi::ReturnCode l_rc; + + // Gather data that needs to be stored. For testing purposes we will just + // set an abitrary number. + //l_rc = setSavedData( 0xdeadbeef ); if(l_rc) return l_rc; + //printf( "Saved data: 0x%08x\n", getSavedData() ); + + // Make sure maint logic in valid state to run new cmd + l_rc = preConditionCheck(); if(l_rc) return l_rc; + + // Load cmd type: MBMCTQ + l_rc = loadCmdType(); if(l_rc) return l_rc; + + // Load start address: MBMACAQ + l_rc = loadStartAddress(); if(l_rc) return l_rc; + + // Load stop conditions: MBASCTLQ + l_rc = loadStopCondMask(); if(l_rc) return l_rc; + + // Start the command: MBMCCQ + l_rc = startMaintCmd(); if(l_rc) return l_rc; + + // Check for early problems with maint cmd instead of waiting for + // cmd timeout + l_rc = postConditionCheck(); if(l_rc) return l_rc; + + if(iv_poll == false) + { + FAPI_INF("Cmd has started. Use attentions to detect cmd complete."); + return l_rc; + } + + // Poll for command complete: MBMSRQ + l_rc = pollForMaintCmdComplete(); if(l_rc) return l_rc; + + // Read the data from the display cmd: MBMSRQ + + static const uint32_t maintBufferReadDataRegs[16]={ + MAINT0_MBA_MAINT_BUFF0_DATA0_0x03010655, + MAINT0_MBA_MAINT_BUFF0_DATA1_0x03010656, + MAINT0_MBA_MAINT_BUFF0_DATA2_0x03010657, + MAINT0_MBA_MAINT_BUFF0_DATA3_0x03010658, + + MAINT0_MBA_MAINT_BUFF1_DATA0_0x03010665, + MAINT0_MBA_MAINT_BUFF1_DATA1_0x03010666, + MAINT0_MBA_MAINT_BUFF1_DATA2_0x03010667, + MAINT0_MBA_MAINT_BUFF1_DATA3_0x03010668, + + MAINT0_MBA_MAINT_BUFF2_DATA0_0x03010675, + MAINT0_MBA_MAINT_BUFF2_DATA1_0x03010676, + MAINT0_MBA_MAINT_BUFF2_DATA2_0x03010677, + MAINT0_MBA_MAINT_BUFF2_DATA3_0x03010678, + + MAINT0_MBA_MAINT_BUFF3_DATA0_0x03010685, + MAINT0_MBA_MAINT_BUFF3_DATA1_0x03010686, + MAINT0_MBA_MAINT_BUFF3_DATA2_0x03010687, + MAINT0_MBA_MAINT_BUFF3_DATA3_0x03010688}; + + static const uint32_t maintBufferRead65thByteRegs[4]={ + MAINT0_MBA_MAINT_BUFF_65TH_BYTE_64B_ECC0_0x03010695, + MAINT0_MBA_MAINT_BUFF_65TH_BYTE_64B_ECC1_0x03010696, + MAINT0_MBA_MAINT_BUFF_65TH_BYTE_64B_ECC2_0x03010697, + MAINT0_MBA_MAINT_BUFF_65TH_BYTE_64B_ECC3_0x03010698}; + + + uint32_t loop = 0; + ecmdDataBufferBase l_data(64); + + //---------------------------------------------------- + // Read the data: 16 loops x 64bits = 128B cacheline + //---------------------------------------------------- + FAPI_INF("Read the data: 16 loops x 64bits = 128B cacheline"); + + for(loop=0; loop<16; loop++ ) + { + l_rc = fapiGetScom(iv_target, maintBufferReadDataRegs[loop], l_data); + if(l_rc) return l_rc; + FAPI_INF("0x%.8X 0x%.8X", l_data.getWord(0), l_data.getWord(1)); + } + + //---------------------------------------------------- + // Read the 65th byte: 4 loops + //---------------------------------------------------- + FAPI_INF("Read the 65th byte: 4 loops"); + + for(loop=0; loop<4; loop++ ) + { + l_rc = fapiGetScom(iv_target, maintBufferRead65thByteRegs[loop], l_data); + if(l_rc) return l_rc; + FAPI_INF("0x%.8X 0x%.8X", l_data.getWord(0), l_data.getWord(1)); + } + + // Collect FFDC + l_rc = collectFFDC(); if(l_rc) return l_rc; + + FAPI_INF("EXIT Display::setupAndExecuteCmd()"); + + return l_rc; + +} + + +//------------------------------------------------------------------------------ +// Increment MBMACA Address +//------------------------------------------------------------------------------ + +const mss_MaintCmd::CmdType mss_IncrementAddress::cv_cmdType = INCREMENT_MBMACA_ADDRESS; + +//--------------------------------------------------------- +// IncrementAddress Constructor +//--------------------------------------------------------- + +mss_IncrementAddress::mss_IncrementAddress( const fapi::Target & i_target ): + + mss_MaintCmd( i_target, + ecmdDataBufferBase(64), // i_startAddr not used for this cmd + ecmdDataBufferBase(64), // i_endAddr not used for this cmd + NO_STOP_CONDITIONS, // i_stopCondition not used for this cmd + true, // i_poll always true for this cmd + cv_cmdType){} + +//--------------------------------------------------------- +// mss_IncrementAddress setupAndExecuteCmd +//--------------------------------------------------------- + +fapi::ReturnCode mss_IncrementAddress::setupAndExecuteCmd() +{ + + + FAPI_INF("ENTER mss_IncrementAddress::setupAndExecuteCmd()"); + + + fapi::ReturnCode l_rc; + uint32_t l_ecmd_rc = 0; + ecmdDataBufferBase l_mbspa_mask(64); + ecmdDataBufferBase l_mbspa_mask_original(64); + ecmdDataBufferBase l_mbspa_and(64); + + // Read MBSPA MASK + l_rc = fapiGetScom(iv_target, MBA01_MBSPAMSKQ_0x03010614, l_mbspa_mask); + if(l_rc) return l_rc; + + // Save original mask value so we can restore it when done + l_ecmd_rc |= l_mbspa_mask_original.insert(l_mbspa_mask, 0, 64, 0); + + // Mask bits 0 and 8, to hide the special attentions when the cmd completes + l_ecmd_rc |= l_mbspa_mask.setBit(0); + l_ecmd_rc |= l_mbspa_mask.setBit(8); + if(l_ecmd_rc) + { + l_rc.setEcmdError(l_ecmd_rc); + return l_rc; + } + + // Write MBSPA MASK + l_rc = fapiPutScom(iv_target, MBA01_MBSPAMSKQ_0x03010614, l_mbspa_mask); + if(l_rc) return l_rc; + + // Make sure maint logic in valid state to run new cmd + l_rc = preConditionCheck(); if(l_rc) return l_rc; + + // Load cmd type: MBMCTQ + l_rc = loadCmdType(); if(l_rc) return l_rc; + + // Read start address: MBMACAQ + ecmdDataBufferBase l_mbmacaq(64); + l_rc = fapiGetScom(iv_target, MBA01_MBMACAQ_0x0301060D, l_mbmacaq); + if(l_rc) return l_rc; + FAPI_INF("MBMACAQ = 0x%.8X 0x%.8X", l_mbmacaq.getWord(0), l_mbmacaq.getWord(1)); + + // Start the command: MBMCCQ + l_rc = startMaintCmd(); if(l_rc) return l_rc; + + // Check for early problems with maint cmd instead of waiting for + // cmd timeout + l_rc = postConditionCheck(); if(l_rc) return l_rc; + + // Poll for command complete: MBMSRQ + l_rc = pollForMaintCmdComplete(); if(l_rc) return l_rc; + + // Read incremented start address: MBMACAQ + l_rc = fapiGetScom(iv_target, MBA01_MBMACAQ_0x0301060D, l_mbmacaq); + if(l_rc) return l_rc; + + // Collect FFDC + l_rc = collectFFDC(); if(l_rc) return l_rc; + + // Clear bits 0 and 8 in MBSPA AND register + l_ecmd_rc |= l_mbspa_and.flushTo1(); + l_ecmd_rc |= l_mbspa_and.clearBit(0); + l_ecmd_rc |= l_mbspa_and.clearBit(8); + if(l_ecmd_rc) + { + l_rc.setEcmdError(l_ecmd_rc); + return l_rc; + } + + // Write MPSPA AND register + l_rc = fapiPutScom(iv_target, MBA01_MBSPAQ_AND_0x03010612, l_mbspa_and); + if(l_rc) return l_rc; + + // Restore MBSPA MASK + l_rc = fapiPutScom(iv_target, MBA01_MBSPAMSKQ_0x03010614, l_mbspa_mask_original); + if(l_rc) return l_rc; + + + FAPI_INF("EXIT mss_IncrementAddress::setupAndExecuteCmd()"); + + return l_rc; +} + + +//------------------------------------------------------------------------------ +// mss_TimeBaseScrub +//------------------------------------------------------------------------------ + +const mss_MaintCmd::CmdType mss_TimeBaseScrub::cv_cmdType = TIMEBASE_SCRUB; + +//--------------------------------------------------------- +// mss_TimeBaseScrub Constructor +//--------------------------------------------------------- + +mss_TimeBaseScrub::mss_TimeBaseScrub( const fapi::Target & i_target, + const ecmdDataBufferBase & i_startAddr, + const ecmdDataBufferBase & i_endAddr, + TimeBaseSpeed i_speed, + uint32_t i_stopCondition, + bool i_poll ) : + mss_MaintCmd( i_target, + i_startAddr, + i_endAddr, + i_stopCondition, + i_poll, + cv_cmdType), + + // NOTE: iv_speed is instance variable of TimeBaseScrub, since not + // needed in parent class + iv_speed( i_speed ) + {} + + + +//--------------------------------------------------------- +// mss_TimeBaseScrub setupAndExecuteCmd +//--------------------------------------------------------- + +fapi::ReturnCode mss_TimeBaseScrub::setupAndExecuteCmd() +{ + FAPI_INF("ENTER mss_TimeBaseScrub::setupAndExecuteCmd()"); + + fapi::ReturnCode l_rc; + + // Gather data that needs to be stored. For testing purposes we will just + // set an abitrary number. + //l_rc = setSavedData( 0xdeadbeef ); if(l_rc) return l_rc; + //printf( "Saved data: 0x%08x\n", getSavedData() ); + + // Make sure maint logic in valid state to run new cmd + l_rc = preConditionCheck(); if(l_rc) return l_rc; + + // Load cmd type: MBMCTQ + l_rc = loadCmdType(); if(l_rc) return l_rc; + + // Load start address: MBMACAQ + l_rc = loadStartAddress(); if(l_rc) return l_rc; + + // Load end address: MBMEAQ + l_rc = loadEndAddress(); if(l_rc) return l_rc; + + // Load speed: MBMCTQ + l_rc = loadSpeed(iv_speed); if(l_rc) return l_rc; + + // Load stop conditions: MBASCTLQ + l_rc = loadStopCondMask(); if(l_rc) return l_rc; + + /* + // DEBUG. Set hard CE threshold to 1: MBSTRQ + FAPI_INF("\nDEBUG. Set hard CE threshold to 1: MBSTRQ"); + ecmdDataBufferBase l_data(64); + uint32_t l_hardCEThreshold = 1; + l_rc = fapiGetScom(iv_target, MBS01_MBSTRQ_0x02011655, l_data); + if(l_rc) return l_rc; + l_data.insert( l_hardCEThreshold, 28, 12, 32-12 ); // 28:39 hard ce threshold + l_data.setBit(2); // Enable hard ce ETE special attention + l_data.setBit(57); // Enable per-symbol counters to count hard ces + l_rc = fapiPutScom(iv_target, MBS01_MBSTRQ_0x02011655, l_data); + if(l_rc) return l_rc; + */ + + // Start the command: MBMCCQ + l_rc = startMaintCmd(); if(l_rc) return l_rc; + + // Check for early problems with maint cmd instead of waiting for + // cmd timeout + l_rc = postConditionCheck(); if(l_rc) return l_rc; + + if(iv_poll == false) + { + FAPI_INF("Cmd has started. Use attentions to detect cmd complete."); + return l_rc; + } + + // Poll for command complete: MBMSRQ + l_rc = pollForMaintCmdComplete(); if(l_rc) return l_rc; + + // Collect FFDC + l_rc = collectFFDC(); if(l_rc) return l_rc; + + FAPI_INF("EXIT mss_TimeBaseScrub::setupAndExecuteCmd()"); + + return l_rc; + +} + + +//------------------------------------------------------------------------------ +// mss_TimeBaseSteerCleanup +//------------------------------------------------------------------------------ + +const mss_MaintCmd::CmdType mss_TimeBaseSteerCleanup::cv_cmdType = TIMEBASE_STEER_CLEANUP; + +//--------------------------------------------------------- +// mss_TimeBaseSteerCleanup Constructor +//--------------------------------------------------------- + +mss_TimeBaseSteerCleanup::mss_TimeBaseSteerCleanup( const fapi::Target & i_target, + const ecmdDataBufferBase & i_startAddr, + const ecmdDataBufferBase & i_endAddr, + TimeBaseSpeed i_speed, + uint32_t i_stopCondition, + bool i_poll ) : + mss_MaintCmd( i_target, + i_startAddr, + i_endAddr, + i_stopCondition, + i_poll, + cv_cmdType), + + // NOTE: iv_speed is instance variable of TimeBaseSteerCleanup, since not + // needed in parent class + iv_speed( i_speed ) + {} + + + +//--------------------------------------------------------- +// mss_TimeBaseSteerCleanup setupAndExecuteCmd +//--------------------------------------------------------- + +fapi::ReturnCode mss_TimeBaseSteerCleanup::setupAndExecuteCmd() +{ + FAPI_INF("ENTER mss_TimeBaseSteerCleanup::setupAndExecuteCmd()"); + + fapi::ReturnCode l_rc; + + // Gather data that needs to be stored. For testing purposes we will just + // set an abitrary number. + //l_rc = setSavedData( 0xdeadbeef ); if(l_rc) return l_rc; + //printf( "Saved data: 0x%08x\n", getSavedData() ); + + // Make sure maint logic in valid state to run new cmd + l_rc = preConditionCheck(); if(l_rc) return l_rc; + + // Load cmd type: MBMCTQ + l_rc = loadCmdType(); if(l_rc) return l_rc; + + // Load start address: MBMACAQ + l_rc = loadStartAddress(); if(l_rc) return l_rc; + + // Load end address: MBMEAQ + l_rc = loadEndAddress(); if(l_rc) return l_rc; + + // Load speed: MBMCTQ + // TODO: May be able to go faster during IPL than runtime, since don't + // have to worry about hanging fetch traffic during IPL. + l_rc = loadSpeed(iv_speed); if(l_rc) return l_rc; + + // Load stop conditions: MBASCTLQ + l_rc = loadStopCondMask(); if(l_rc) return l_rc; + + // Start the command: MBMCCQ + l_rc = startMaintCmd(); if(l_rc) return l_rc; + + // Check for early problems with maint cmd instead of waiting for + // cmd timeout + l_rc = postConditionCheck(); if(l_rc) return l_rc; + + if(iv_poll == false) + { + FAPI_INF("Cmd has started. Use attentions to detect cmd complete."); + return l_rc; + } + + // Poll for command complete: MBMSRQ + l_rc = pollForMaintCmdComplete(); if(l_rc) return l_rc; + + // Collect FFDC + l_rc = collectFFDC(); if(l_rc) return l_rc; + + FAPI_INF("EXIT mss_TimeBaseSteerCleanup::setupAndExecuteCmd()"); + + return l_rc; + +} + + + +//------------------------------------------------------------------------------ +// Utility funcitons +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +// mss_get_address_range +//------------------------------------------------------------------------------ +fapi::ReturnCode mss_get_address_range( const fapi::Target & i_target, + uint8_t i_rank, + ecmdDataBufferBase & o_startAddr, + ecmdDataBufferBase & o_endAddr ) +{ + + + FAPI_INF("ENTER mss_get_address_range()"); + + static const uint8_t memConfigType[9][4][2]={ + + // Refer to Centaur Workbook: 5.2 Master and Slave Rank Usage + // + // SUBTYPE_A SUBTYPE_B SUBTYPE_C SUBTYPE_D + // + //SLOT_0_ONLY SLOT_0_AND_1 SLOT_0_ONLY SLOT_0_AND_1 SLOT_0_ONLY SLOT_0_AND_1 SLOT_0_ONLY SLOT_0_AND_1 + // + //master slave master slave master slave master slave master slave master slave master slave master slave + // + {{0xff, 0xff}, {0xff, 0xff}, {0xff, 0xff}, {0xff, 0xff}}, // TYPE_0 + {{0x00, 0x40}, {0x10, 0x50}, {0x30, 0x70}, {0xff, 0xff}}, // TYPE_1 + {{0x01, 0x41}, {0x03, 0x43}, {0x07, 0x47}, {0xff, 0xff}}, // TYPE_2 + {{0x11, 0x51}, {0x13, 0x53}, {0x17, 0x57}, {0xff, 0xff}}, // TYPE_3 + {{0x31, 0x71}, {0x33, 0x73}, {0x37, 0x77}, {0xff, 0xff}}, // TYPE_4 + {{0x00, 0x40}, {0x10, 0x50}, {0x30, 0x70}, {0xff, 0xff}}, // TYPE_5 + {{0x01, 0x41}, {0x03, 0x43}, {0x07, 0x47}, {0xff, 0xff}}, // TYPE_6 + {{0x11, 0x51}, {0x13, 0x53}, {0x17, 0x57}, {0xff, 0xff}}, // TYPE_7 + {{0x31, 0x71}, {0x33, 0x73}, {0x37, 0x77}, {0xff, 0xff}}}; // TYPE_8 + // TODO: Need to update when 5D config confirmed. + + fapi::ReturnCode l_rc; + uint32_t l_ecmd_rc = 0; + ecmdDataBufferBase l_data(64); + mss_MemConfig::MemOrg l_row; + mss_MemConfig::MemOrg l_col; + mss_MemConfig::MemOrg l_bank; + uint32_t l_dramSize = 0; + uint8_t l_dramWidth = 0; + fapi::Target l_targetCentaur; + uint8_t l_mbaPosition = 0; + uint8_t l_isSIM = 1; + + uint8_t l_slotConfig = 0; + uint8_t l_configType = 0; + uint8_t l_configSubType = 0; + uint8_t l_end_master_rank = 0; + uint8_t l_end_slave_rank = 0; + + // Get Centaur target for the given MBA + l_rc = fapiGetParentChip(i_target, l_targetCentaur); + if(l_rc) + { + FAPI_ERR("Error getting Centaur parent target for the given MBA"); + return l_rc; + } + + // Get MBA position: 0 = mba01, 1 = mba23 + l_rc = FAPI_ATTR_GET(ATTR_CHIP_UNIT_POS, &i_target, l_mbaPosition); + if(l_rc) + { + FAPI_ERR("Error getting MBA position"); + return l_rc; + } + + // Check system attribute if sim: 1 = Awan/HWSimulator. 0 = Simics/RealHW. + l_rc = FAPI_ATTR_GET(ATTR_IS_SIMULATION, NULL, l_isSIM); + if(l_rc) + { + FAPI_ERR("Error getting ATTR_IS_SIMULATION"); + return l_rc; + } + + // Get l_dramWidth + l_rc = FAPI_ATTR_GET(ATTR_EFF_DRAM_WIDTH, &i_target, l_dramWidth); + if(l_rc) + { + FAPI_ERR("Error getting DRAM width"); + return l_rc; + } + + // Check MBAXCRn, to show memory configured behind this MBA + l_rc = fapiGetScom(l_targetCentaur, mss_mbaxcr[l_mbaPosition], l_data); + if(l_rc) return l_rc; + if (l_data.isBitClear(0,4)) + { + FAPI_ERR("MBAXCRn[0:3] = 0, meaning no memory configured behind this MBA."); + + // TODO: Calling out FW high + // FFDC: MBA target + const fapi::Target & MBA = i_target; + // FFDC: Capture register we are checking + ecmdDataBufferBase & MBAXCR = l_data; + + // Create new log. + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_NO_MEM_CNFG); + return l_rc; + } + + //******************************************************************** + // Find max row/col/bank, based on l_dramSize and l_dramWidth + //******************************************************************** + + // Get l_dramSize + l_ecmd_rc |= l_data.extractPreserve(&l_dramSize, 6, 2, 32-2); // (6:7) + if(l_ecmd_rc) + { + l_rc.setEcmdError(l_ecmd_rc); + return l_rc; + } + + if((l_dramWidth == mss_MemConfig::X8) && (l_dramSize == mss_MemConfig::GBIT_2)) + { + // For memory part Size = 256Mbx8 (2Gb), row/col/bank = 15/10/3 + FAPI_INF("For memory part Size = 256Mbx8 (2Gb), row/col/bank = 15/10/3"); + l_row = mss_MemConfig::ROW_15; + l_col = mss_MemConfig::COL_10; + l_bank = mss_MemConfig::BANK_3; + } + else if((l_dramWidth == mss_MemConfig::X4) && (l_dramSize == mss_MemConfig::GBIT_2)) + { + // For memory part Size = 512Mbx4 (2Gb), row/col/bank = 15/11/3 + FAPI_INF("For memory part Size = 512Mbx4 (2Gb), row/col/bank = 15/11/3"); + l_row = mss_MemConfig::ROW_15; + l_col = mss_MemConfig::COL_11; + l_bank = mss_MemConfig::BANK_3; + } + else if((l_dramWidth == mss_MemConfig::X8) && (l_dramSize == mss_MemConfig::GBIT_4)) + { + // For memory part Size = 512Mbx8 (4Gb), row/col/bank = 16/10/3 + FAPI_INF("For memory part Size = 512Mbx8 (4Gb), row/col/bank = 16/10/3"); + l_row = mss_MemConfig::ROW_16; + l_col = mss_MemConfig::COL_10; + l_bank = mss_MemConfig::BANK_3; + } + else if((l_dramWidth == mss_MemConfig::X4) && (l_dramSize == mss_MemConfig::GBIT_4)) + { + // For memory part Size = 1Gbx4 (4Gb), row/col/bank = 16/11/3 + FAPI_INF("For memory part Size = 1Gbx4 (4Gb), row/col/bank = 16/11/3"); + l_row = mss_MemConfig::ROW_16; + l_col = mss_MemConfig::COL_11; + l_bank = mss_MemConfig::BANK_3; + } + else if((l_dramWidth == mss_MemConfig::X8) && (l_dramSize == mss_MemConfig::GBIT_8)) + { + // For memory part Size = 1Gbx8 (8Gb), row/col/bank = 16/11/3 + FAPI_INF("For memory part Size = 1Gbx8 (8Gb), row/col/bank = 16/11/3"); + l_row = mss_MemConfig::ROW_16; + l_col = mss_MemConfig::COL_11; + l_bank = mss_MemConfig::BANK_3; + } + else if((l_dramWidth == mss_MemConfig::X4) && (l_dramSize == mss_MemConfig::GBIT_8)) + { + // For memory part Size = 2Gbx4 (8Gb), row/col/bank = 16/12/3 + FAPI_INF("For memory part Size = 2Gbx4 (8Gb), row/col/bank = 16/12/3"); + l_row = mss_MemConfig::ROW_16; + l_col = mss_MemConfig::COL_12; + l_bank = mss_MemConfig::BANK_3; + } + else + { + FAPI_ERR("Invalid l_dramSize = %d or l_dramWidth = %d in MBAXCRn.", l_dramSize, l_dramWidth ); + + // TODO: Calling out FW high + // FFDC: MBA target + const fapi::Target & MBA = i_target; + // FFDC: Capture register we are checking + ecmdDataBufferBase & MBAXCR = l_data; + + // Create new log. + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_INVALID_DRAM_SIZE_WIDTH); + return l_rc; + } + + + //******************************************************************** + // Find l_end_master_rank and l_end_slave_rank based on DIMM configuration + //******************************************************************** + + // (0:3) Configuration type (1-8) + l_ecmd_rc |= l_data.extractPreserve(&l_configType, 0, 4, 8-4); + + // (4:5) Configuration subtype (A, B, C, D) + l_ecmd_rc |= l_data.extractPreserve(&l_configSubType, 4, 2, 8-2); + + // (8) Slot Configuration + // 0 = Centaur DIMM or IS DIMM, slot0 only, 1 = IS DIMM slots 0 and 1 + l_ecmd_rc |= l_data.extractPreserve(&l_slotConfig, 8, 1, 8-1); + if(l_ecmd_rc) + { + l_rc.setEcmdError(l_ecmd_rc); + return l_rc; + } + + + FAPI_INF("memConfigType[%d][%d][%d] = 0x%02x", + l_configType,l_configSubType,l_slotConfig, + memConfigType[l_configType][l_configSubType][l_slotConfig]); + + l_end_master_rank = (memConfigType[l_configType][l_configSubType][l_slotConfig] & 0xf0) >> 4; + l_end_slave_rank = memConfigType[l_configType][l_configSubType][l_slotConfig] & 0x0f; + + FAPI_INF("end master rank = %d, end slave rank = %d", l_end_master_rank, l_end_slave_rank); + + if ((l_end_master_rank == 0x0f) || (l_end_slave_rank == 0x0f)) + { + FAPI_ERR("MBAXCRn configured with unsupported combination of l_configType, l_configSubType, l_slotConfig"); + + // TODO: Calling out FW high + // FFDC: MBA target + const fapi::Target & MBA = i_target; + // FFDC: Capture register we are checking + ecmdDataBufferBase & MBAXCR = l_data; + + // Create new log. + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_INVALID_DIMM_CNFG); + return l_rc; + } + + //******************************************************************** + // Get address range for all ranks configured behind this MBA + //******************************************************************** + if (i_rank == MSS_ALL_RANKS) + { + FAPI_INF("Get address range for rank = ALL_RANKS"); + + // Start address is just rank 0 with row/col/bank all 0's + o_startAddr.flushTo0(); + + // If Awan/HWSimulator, end address is just start address +3 + if (l_isSIM) + { + FAPI_INF("ATTR_IS_SIMULATION = 1, Awan/HWSimulator, so use smaller address range."); + + + // Do only rank0, row0, all banks all cols + l_end_master_rank = 0; + l_end_slave_rank = 0; + + uint32_t l_row_zero = 0; + l_ecmd_rc |= o_endAddr.flushTo0(); + + // MASTER RANK = 0:3 + l_ecmd_rc |= o_endAddr.insert( l_end_master_rank, 0, 4, 8-4 ); + + // SLAVE RANK = 4:6 + l_ecmd_rc |= o_endAddr.insert( l_end_slave_rank, 4, 3, 8-3 ); + + // BANK = 7:10 + l_ecmd_rc |= o_endAddr.insert( (uint32_t)l_bank, 7, 4, 32-4 ); + + // ROW = 11:27 + l_ecmd_rc |= o_endAddr.insert( (uint32_t)l_row_zero, 11, 17, 32-17 ); + + // COL = 28:39, note: c2, c1, c0 always 0 + l_ecmd_rc |= o_endAddr.insert( (uint32_t)l_col, 28, 12, 32-12 ); + + + } + // Else, set end address to be last address of l_end_master_rank + else + { + l_ecmd_rc |= o_endAddr.flushTo0(); + + // MASTER RANK = 0:3 + l_ecmd_rc |= o_endAddr.insert( l_end_master_rank, 0, 4, 8-4 ); + + // SLAVE RANK = 4:6 + l_ecmd_rc |= o_endAddr.insert( l_end_slave_rank, 4, 3, 8-3 ); + + // BANK = 7:10 + l_ecmd_rc |= o_endAddr.insert( (uint32_t)l_bank, 7, 4, 32-4 ); + + // ROW = 11:27 + l_ecmd_rc |= o_endAddr.insert( (uint32_t)l_row, 11, 17, 32-17 ); + + // COL = 28:39, note: c2, c1, c0 always 0 + l_ecmd_rc |= o_endAddr.insert( (uint32_t)l_col, 28, 12, 32-12 ); + } + } + + //******************************************************************** + // Get address range for single rank configured behind this MBA + //******************************************************************** + else + { + FAPI_INF("Get address range for master rank = %d\n", i_rank ); + + // Check for i_rank out of range + if (i_rank>=8) + { + FAPI_ERR("i_rank input to mss_get_address_range out of range"); + // TODO: Calling out FW high + // FFDC: MBA target + const fapi::Target & MBA = i_target; + // FFDC: Capture i_rank; + uint8_t RANK = i_rank; + + // Create new log. + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_GET_ADDRESS_RANGE_BAD_INPUT); + return l_rc; + } + + // NOTE: If this rank is not valid, we should see MBAFIR[1]: invalid + // maint address, when cmd started + + // DEBUG - run on last few address of the rank + /* + // Set end address to end of rank + l_ecmd_rc |= o_endAddr.flushTo0(); + l_ecmd_rc |= o_endAddr.insert( i_rank, 0, 4, 8-4 ); + l_ecmd_rc |= o_endAddr.insert( (uint32_t)l_bank, 7, 4, 32-4 ); + l_ecmd_rc |= o_endAddr.insert( (uint32_t)l_row, 11, 17, 32-17 ); + l_ecmd_rc |= o_endAddr.insert( (uint32_t)l_col, 28, 12, 32-12 ); + + + // Set start address so we do all banks/cols in last row of the rank + uint32_t l_bank_zero = 0; + uint32_t l_col_zero = 0; + l_ecmd_rc |= o_startAddr.flushTo0(); + l_ecmd_rc |= o_startAddr.insert( i_rank, 0, 4, 8-4 ); + l_ecmd_rc |= o_startAddr.insert( (uint32_t)l_bank_zero, 7, 4, 32-4 ); + l_ecmd_rc |= o_startAddr.insert( (uint32_t)l_row, 11, 17, 32-17 ); + l_ecmd_rc |= o_startAddr.insert( (uint32_t)l_col_zero, 28, 12, 32-12 ); + */ + // DEBUG - run on last few address of the rank + + + // Start address is just i_rank with row/col/bank all 0's + l_ecmd_rc |= o_startAddr.flushTo0(); + + // MASTER RANK = 0:3 + l_ecmd_rc |= o_startAddr.insert( i_rank, 0, 4, 8-4 ); + + // If Awan/HWSimulator, end address is just start address +3 + if (l_isSIM) + { + FAPI_INF("ATTR_IS_SIMULATION = 1, Awan/HWSimulator, so use smaller address range."); + + l_end_slave_rank = 0; + + uint32_t l_row_zero = 0; + l_ecmd_rc |= o_endAddr.flushTo0(); + // MASTER RANK = 0:3 + l_ecmd_rc |= o_endAddr.insert( i_rank, 0, 4, 8-4 ); + + // SLAVE RANK = 4:6 + l_ecmd_rc |= o_endAddr.insert( l_end_slave_rank, 4, 3, 8-3 ); + + // BANK = 7:10 + l_ecmd_rc |= o_endAddr.insert( (uint32_t)l_bank, 7, 4, 32-4 ); + // ROW = 11:27 + l_ecmd_rc |= o_endAddr.insert( (uint32_t)l_row_zero, 11, 17, 32-17 ); + // COL = 28:39, note: c2, c1, c0 always 0 + l_ecmd_rc |= o_endAddr.insert( (uint32_t)l_col, 28, 12, 32-12 ); + + } + // Else, set end address to be last address of i_rank + else + { + l_ecmd_rc |= o_endAddr.flushTo0(); + // MASTER RANK = 0:3 + l_ecmd_rc |= o_endAddr.insert( i_rank, 0, 4, 8-4 ); + + // SLAVE RANK = 4:6 + l_ecmd_rc |= o_endAddr.insert( l_end_slave_rank, 4, 3, 8-3 ); + + // BANK = 7:10 + l_ecmd_rc |= o_endAddr.insert( (uint32_t)l_bank, 7, 4, 32-4 ); + // ROW = 11:27 + l_ecmd_rc |= o_endAddr.insert( (uint32_t)l_row, 11, 17, 32-17 ); + // COL = 28:36 + l_ecmd_rc |= o_endAddr.insert( (uint32_t)l_col, 28, 12, 32-12 ); + } + + } + + if(l_ecmd_rc) + { + l_rc.setEcmdError(l_ecmd_rc); + return l_rc; + } + + + + FAPI_INF("EXIT mss_get_address_range()"); + + return l_rc; +} + + + + + +//------------------------------------------------------------------------------ +// mss_get_mark_store +//------------------------------------------------------------------------------ +fapi::ReturnCode mss_get_mark_store( const fapi::Target & i_target, + uint8_t i_rank, + uint8_t & o_symbolMark, + uint8_t & o_chipMark ) +{ + + fapi::ReturnCode l_rc; + uint32_t l_ecmd_rc = 0; + ecmdDataBufferBase l_markstore(64); + ecmdDataBufferBase l_mbeccfir(64); + ecmdDataBufferBase l_data(64); + uint8_t l_dramWidth = 0; + uint8_t l_symbolMarkGalois = 0; + uint8_t l_chipMarkGalois = 0; + uint8_t l_symbolsPerChip = 4; + fapi::Target l_targetCentaur; + uint8_t l_mbaPosition = 0; + + o_symbolMark = MSS_INVALID_SYMBOL; + o_chipMark = MSS_INVALID_SYMBOL; + + // Get Centaur target for the given MBA + l_rc = fapiGetParentChip(i_target, l_targetCentaur); + if(l_rc) + { + FAPI_ERR("Error getting Centaur parent target for the given MBA"); + return l_rc; + } + + + // Get MBA position: 0 = mba01, 1 = mba23 + l_rc = FAPI_ATTR_GET(ATTR_CHIP_UNIT_POS, &i_target, l_mbaPosition); + if(l_rc) + { + FAPI_ERR("Error getting MBA position"); + return l_rc; + } + + // Get l_dramWidth + l_rc = FAPI_ATTR_GET(ATTR_EFF_DRAM_WIDTH, &i_target, l_dramWidth); + if(l_rc) + { + FAPI_ERR("Error getting DRAM width"); + return l_rc; + } + + // Check for i_rank out of range + if (i_rank>=8) + { + FAPI_ERR("i_rank input to mss_get_mark_store out of range"); + // TODO: Calling out FW high + // FFDC: MBA target + const fapi::Target & MBA = i_target; + // FFDC: Capture i_rank; + uint8_t RANK = i_rank; + + // Create new log. + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_GET_MARK_STORE_BAD_INPUT); + return l_rc; + } + + // Read markstore register for the given rank + l_rc = fapiGetScom(l_targetCentaur, mss_markStoreRegs[i_rank][l_mbaPosition], l_markstore); + if(l_rc) return l_rc; + + // If MPE FIR for the given rank (scrub or fetch) is on after the read, + // we will read one more time just to make sure we get latest. + l_rc = fapiGetScom(l_targetCentaur, mss_mbeccfir[l_mbaPosition], l_mbeccfir); + if(l_rc) return l_rc; + if (l_mbeccfir.isBitSet(i_rank) || l_mbeccfir.isBitSet(20 + i_rank)) + { + l_rc = fapiGetScom(l_targetCentaur, mss_markStoreRegs[i_rank][l_mbaPosition], l_markstore); + if(l_rc) return l_rc; + } + + // Get l_symbolMarkGalois + l_ecmd_rc |= l_markstore.extractPreserve(&l_symbolMarkGalois, 0, 8, 8-8); + if(l_ecmd_rc) + { + l_rc.setEcmdError(l_ecmd_rc); + return l_rc; + } + + if (l_symbolMarkGalois == 0x00) // No symbol mark + { + o_symbolMark = MSS_INVALID_SYMBOL; + } + else if (l_dramWidth == mss_MemConfig::X4) + { + FAPI_ERR("l_symbolMarkGalois invalid: symbol mark not allowed in x4 mode."); + + // TODO: Calling out FW high + // FFDC: MBA target + const fapi::Target & MBA = i_target; + // FFDC: DRAM width + uint8_t DRAM_WIDTH = l_dramWidth; + // FFDC: Capure i_rank; + uint8_t RANK = i_rank; + // FFDC: Capture markstore + ecmdDataBufferBase & MARKSTORE = l_markstore; + + // Create new log. + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_X4_SYMBOL_ON_READ); + return l_rc; + } + else // Converted from galois field to symbol index + { + o_symbolMark = MSS_SYMBOLS_PER_RANK; + for ( uint32_t i = 0; i < MSS_SYMBOLS_PER_RANK; i++ ) + { + if ( l_symbolMarkGalois == mss_symbol2Galois[i] ) + { + o_symbolMark = i; + break; + } + } + + if ( MSS_SYMBOLS_PER_RANK <= o_symbolMark ) + { + FAPI_ERR("Invalid galois field in markstore."); + + // TODO: Calling out FW high + // FFDC: MBA target + const fapi::Target & MBA = i_target; + // FFDC: DRAM width + uint8_t DRAM_WIDTH = l_dramWidth; + // FFDC: Capure i_rank; + uint8_t RANK = i_rank; + // FFDC: Capture markstore + ecmdDataBufferBase & MARKSTORE = l_markstore; + + // Create new log. + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_INVALID_MARKSTORE); + return l_rc; + } + } + + // Get l_chipMarkGalois + l_ecmd_rc |= l_markstore.extractPreserve(&l_chipMarkGalois, 8, 8, 8-8); + if(l_ecmd_rc) + { + l_rc.setEcmdError(l_ecmd_rc); + return l_rc; + } + + + if (l_chipMarkGalois == 0x00) // No chip mark + { + o_chipMark = MSS_INVALID_SYMBOL; + } + else // Converted from galois field to chip index + { + + if (l_dramWidth == mss_MemConfig::X4) + { + l_symbolsPerChip = 2; + } + else if (l_dramWidth == mss_MemConfig::X8) + { + l_symbolsPerChip = 4; + } + + o_chipMark = MSS_SYMBOLS_PER_RANK; + for ( uint32_t i = 0; i < MSS_SYMBOLS_PER_RANK; i=i+l_symbolsPerChip) + { + if ( l_chipMarkGalois == mss_symbol2Galois[i] ) + { + o_chipMark = i; + break; + } + } + + if ( MSS_SYMBOLS_PER_RANK <= o_chipMark ) + { + FAPI_ERR("Invalid galois field in markstore."); + + // TODO: Calling out FW high + // FFDC: MBA target + const fapi::Target & MBA = i_target; + // FFDC: DRAM width + uint8_t DRAM_WIDTH = l_dramWidth; + // FFDC: Capure i_rank; + uint8_t RANK = i_rank; + // FFDC: Capture markstore + ecmdDataBufferBase & MARKSTORE = l_markstore; + + // Create new log. + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_INVALID_MARKSTORE); + return l_rc; + } + } + + FAPI_INF("mss_get_mark_store(): rank%d, chip mark = %d, symbol mark = %d", + i_rank, o_chipMark, o_symbolMark ); + + return l_rc; +} + + + +//------------------------------------------------------------------------------ +// mss_put_mark_store +//------------------------------------------------------------------------------ +fapi::ReturnCode mss_put_mark_store( const fapi::Target & i_target, + uint8_t i_rank, + uint8_t i_symbolMark, + uint8_t i_chipMark ) +{ + + FAPI_INF("ENTER mss_put_mark_store()"); + + + fapi::ReturnCode l_rc; + uint32_t l_ecmd_rc = 0; + ecmdDataBufferBase l_markstore(64); + ecmdDataBufferBase l_mbeccfir(64); + ecmdDataBufferBase l_data(64); + uint8_t l_dramWidth = 0; + uint8_t l_symbolMarkGalois = 0; + uint8_t l_chipMarkGalois = 0; + fapi::Target l_targetCentaur; + uint8_t l_mbaPosition = 0; + + // Get Centaur target for the given MBA + l_rc = fapiGetParentChip(i_target, l_targetCentaur); + if(l_rc) + { + FAPI_ERR("Error getting Centaur parent target for the given MBA"); + return l_rc; + } + + + // Get MBA position: 0 = mba01, 1 = mba23 + l_rc = FAPI_ATTR_GET(ATTR_CHIP_UNIT_POS, &i_target, l_mbaPosition); + if(l_rc) + { + FAPI_ERR("Error getting MBA position"); + return l_rc; + } + + + // Get l_dramWidth + l_rc = FAPI_ATTR_GET(ATTR_EFF_DRAM_WIDTH, &i_target, l_dramWidth); + if(l_rc) + { + FAPI_ERR("Error getting DRAM width"); + return l_rc; + } + + // Check for i_rank out of range + if (i_rank>=8) + { + FAPI_ERR("i_rank input to mss_put_mark_store out of range"); + // TODO: Calling out FW high + // FFDC: MBA target + const fapi::Target & MBA = i_target; + // FFDC: Capture i_rank; + uint8_t RANK = i_rank; + + // Create new log. + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_PUT_MARK_STORE_BAD_INPUT); + return l_rc; + } + + // Get l_symbolMarkGalois + if (i_symbolMark == MSS_INVALID_SYMBOL) // No symbol mark + { + l_symbolMarkGalois = 0x00; + } + else if ( l_dramWidth == mss_MemConfig::X4 ) + { + FAPI_ERR("i_symbolMark invalid: symbol mark not allowed in x4 mode."); + + // TODO: Calling out FW high + // FFDC: MBA target + const fapi::Target & MBA = i_target; + // FFDC: DRAM width + uint8_t DRAM_WIDTH = l_dramWidth; + // FFDC: Capure i_rank; + uint8_t RANK = i_rank; + // FFDC: Capure i_symbolMark; + uint8_t SYMBOL_MARK = i_symbolMark; + // FFDC: Capure i_chipMark; + uint8_t CHIP_MARK = i_chipMark; + + // Create new log. + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_X4_SYMBOL_ON_WRITE); + return l_rc; + } + else if ( MSS_SYMBOLS_PER_RANK <= i_symbolMark ) + { + FAPI_ERR("i_symbolMark invalid: symbol index out of range."); + + // TODO: Calling out FW high + // FFDC: MBA target + const fapi::Target & MBA = i_target; + // FFDC: DRAM width + uint8_t DRAM_WIDTH = l_dramWidth; + // FFDC: Capure i_rank; + uint8_t RANK = i_rank; + // FFDC: Capure i_symbolMark; + uint8_t SYMBOL_MARK = i_symbolMark; + // FFDC: Capure i_chipMark; + uint8_t CHIP_MARK = i_chipMark; + + // Create new log. + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_INVALID_SYMBOL_INDEX); + return l_rc; + } + else // Convert from symbol index to galois field + { + l_symbolMarkGalois = mss_symbol2Galois[i_symbolMark]; + } + l_ecmd_rc |= l_markstore.insert( l_symbolMarkGalois, 0, 8, 0 ); + + + // Get l_chipMarkGalois + if (i_chipMark == MSS_INVALID_SYMBOL) // No chip mark + { + l_chipMarkGalois = 0x00; + } + else if ( MSS_SYMBOLS_PER_RANK <= i_chipMark ) + { + FAPI_ERR("i_chipMark invalid: symbol index out of range."); + + // TODO: Calling out FW high + // FFDC: MBA target + const fapi::Target & MBA = i_target; + // FFDC: DRAM width + uint8_t DRAM_WIDTH = l_dramWidth; + // FFDC: Capure i_rank; + uint8_t RANK = i_rank; + // FFDC: Capure i_symbolMark; + uint8_t SYMBOL_MARK = i_symbolMark; + // FFDC: Capure i_chipMark; + uint8_t CHIP_MARK = i_chipMark; + + // Create new log. + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_INVALID_SYMBOL_INDEX); + return l_rc; + } + else if ((l_dramWidth == mss_MemConfig::X8) && (i_chipMark % 4) ) + { + FAPI_ERR("i_chipMark invalid: not first symbol index of a x8 chip."); + + // TODO: Calling out FW high + // FFDC: MBA target + const fapi::Target & MBA = i_target; + // FFDC: DRAM width + uint8_t DRAM_WIDTH = l_dramWidth; + // FFDC: Capure i_rank; + uint8_t RANK = i_rank; + // FFDC: Capure i_symbolMark; + uint8_t SYMBOL_MARK = i_symbolMark; + // FFDC: Capure i_chipMark; + uint8_t CHIP_MARK = i_chipMark; + + // Create new log. + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_INVALID_CHIP_INDEX); + return l_rc; + + } + else if ((l_dramWidth == mss_MemConfig::X4) && (i_chipMark % 2) ) + { + FAPI_ERR("i_chipMark invalid: not first symbol index of a x4 chip."); + + // TODO: Calling out FW high + // FFDC: MBA target + const fapi::Target & MBA = i_target; + // FFDC: DRAM width + uint8_t DRAM_WIDTH = l_dramWidth; + // FFDC: Capure i_rank; + uint8_t RANK = i_rank; + // FFDC: Capure i_symbolMark; + uint8_t SYMBOL_MARK = i_symbolMark; + // FFDC: Capure i_chipMark; + uint8_t CHIP_MARK = i_chipMark; + + // Create new log. + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_INVALID_CHIP_INDEX); + return l_rc; + } + else // Convert from symbol index to galois field + { + l_chipMarkGalois = mss_symbol2Galois[i_chipMark]; + } + l_ecmd_rc |= l_markstore.insert( l_chipMarkGalois, 8, 8, 0 ); + if(l_ecmd_rc) + { + l_rc.setEcmdError(l_ecmd_rc); + return l_rc; + } + + // Write markstore register for the given rank + l_rc = fapiPutScom(l_targetCentaur, mss_markStoreRegs[i_rank][l_mbaPosition], l_markstore); + if(l_rc) return l_rc; + + // If MPE FIR for the given rank (scrub or fetch) is on after the write, + // we will return a fapi::ReturnCode to indicate write may not have worked. + // Up to caller to read again if they want to see what new chip mark is. + l_rc = fapiGetScom(l_targetCentaur, mss_mbeccfir[l_mbaPosition], l_mbeccfir); + if(l_rc) return l_rc; + if (l_mbeccfir.isBitSet(i_rank) || l_mbeccfir.isBitSet(20 + i_rank)) + { + // TODO: Can FW distingish this rc from all the others + // so they know they just need to retry after clearing MPR FIR? + + FAPI_ERR("Markstore write may have been blocked due to MPE FIR set."); + + // FFDC: MBA target + const fapi::Target & MBA = i_target; + // FFDC: DRAM width + uint8_t DRAM_WIDTH = l_dramWidth; + // FFDC: Capure i_rank; + uint8_t RANK = i_rank; + // FFDC: Capure i_symbolMark; + uint8_t SYMBOL_MARK = i_symbolMark; + // FFDC: Capure i_chipMark; + uint8_t CHIP_MARK = i_chipMark; + // FFDC: Capture MBECCFIR + ecmdDataBufferBase & MBECCFIR = l_mbeccfir; + + // Create new log. + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_MARKSTORE_WRITE_BLOCKED); + return l_rc; + } + + FAPI_INF("EXIT mss_put_mark_store()"); + return l_rc; +} + + + + +//------------------------------------------------------------------------------ +// mss_get_steer_mux +//------------------------------------------------------------------------------ + +fapi::ReturnCode mss_get_steer_mux( const fapi::Target & i_target, + uint8_t i_rank, + mss_SteerMux::muxType i_muxType, + uint8_t & o_dramSparePort0Symbol, + uint8_t & o_dramSparePort1Symbol, + uint8_t & o_eccSpareSymbol ) +{ + + fapi::ReturnCode l_rc; + uint32_t l_ecmd_rc = 0; + ecmdDataBufferBase l_steerMux(64); + ecmdDataBufferBase l_data(64); + uint8_t l_dramWidth = 0; + uint8_t l_dramSparePort0Index = 0; + uint8_t l_dramSparePort1Index = 0; + uint8_t l_eccSpareIndex = 0; + fapi::Target l_targetCentaur; + uint8_t l_mbaPosition = 0; + + o_dramSparePort0Symbol = MSS_INVALID_SYMBOL; + o_dramSparePort1Symbol = MSS_INVALID_SYMBOL; + o_eccSpareSymbol = MSS_INVALID_SYMBOL; + + // Get Centaur target for the given MBA + l_rc = fapiGetParentChip(i_target, l_targetCentaur); + if(l_rc) + { + FAPI_ERR("Error getting Centaur parent target for the given MBA"); + return l_rc; + } + + + // Get MBA position: 0 = mba01, 1 = mba23 + l_rc = FAPI_ATTR_GET(ATTR_CHIP_UNIT_POS, &i_target, l_mbaPosition); + if(l_rc) + { + FAPI_ERR("Error getting MBA position"); + return l_rc; + } + + // Get l_dramWidth + l_rc = FAPI_ATTR_GET(ATTR_EFF_DRAM_WIDTH, &i_target, l_dramWidth); + if(l_rc) + { + FAPI_ERR("Error getting DRAM width"); + return l_rc; + } + + + // Check for i_rank or i_muxType out of range + if ((i_rank>=8) || + !((i_muxType==mss_SteerMux::READ_MUX) || (i_muxType==mss_SteerMux::WRITE_MUX))) + { + FAPI_ERR("i_rank or i_muxType input to mss_get_steer_mux out of range"); + // TODO: Calling out FW high + // FFDC: MBA target + const fapi::Target & MBA = i_target; + // FFDC: Capture i_rank; + uint8_t RANK = i_rank; + // FFDC: Capure i_muxType + uint8_t MUX_TYPE = i_muxType; + + // Create new log. + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_GET_STEER_MUX_BAD_INPUT); + return l_rc; + } + + + // Read steer mux register for the given rank and mux type (read or write). + if (i_muxType == mss_SteerMux::READ_MUX) + { + // Read muxes are in the MBS + l_rc = fapiGetScom(l_targetCentaur, mss_readMuxRegs[i_rank][l_mbaPosition], l_steerMux); + if(l_rc) return l_rc; + } + else + { + // Write muxes are in the MBA + l_rc = fapiGetScom(i_target, mss_writeMuxRegs[i_rank], l_steerMux); + if(l_rc) return l_rc; + } + + //*************************************** + // Get l_dramSparePort0Index + l_ecmd_rc |= l_steerMux.extractPreserve(&l_dramSparePort0Index, 0, 5, 8-5); + if(l_ecmd_rc) + { + l_rc.setEcmdError(l_ecmd_rc); + return l_rc; + } + + // Get o_dramSparePort0Symbol if index in valid range + if ((l_dramWidth == mss_MemConfig::X8) && (l_dramSparePort0Index < MSS_X8_STEER_OPTIONS_PER_PORT)) + { + o_dramSparePort0Symbol = mss_x8dramSparePort0Index_to_symbol[l_dramSparePort0Index]; + } + else if ((l_dramWidth == mss_MemConfig::X4) && (l_dramSparePort0Index < MSS_X4_STEER_OPTIONS_PER_PORT0)) + { + o_dramSparePort0Symbol = mss_x4dramSparePort0Index_to_symbol[l_dramSparePort0Index]; + } + else + { + FAPI_ERR("Steer mux l_dramSparePort0Index out of range."); + + // TODO: Calling out FW high + // FFDC: MBA target + const fapi::Target & MBA = i_target; + // FFDC: DRAM width + uint8_t DRAM_WIDTH = l_dramWidth; + // FFDC: Capure i_rank; + uint8_t RANK = i_rank; + // FFDC: Capure i_muxType + uint8_t MUX_TYPE = i_muxType; + // FFDC: Capture steer mux + ecmdDataBufferBase & STEER_MUX = l_steerMux; + + // Create new log. + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_INVALID_STEER_MUX); + return l_rc; + } + + + //*************************************** + // Get l_dramSparePort1Index + l_ecmd_rc |= l_steerMux.extractPreserve(&l_dramSparePort1Index, 5, 5, 8-5); + if(l_ecmd_rc) + { + l_rc.setEcmdError(l_ecmd_rc); + return l_rc; + } + + // Get o_dramSparePort1Symbol if index in valid range + if ((l_dramWidth == mss_MemConfig::X8) && (l_dramSparePort1Index < MSS_X8_STEER_OPTIONS_PER_PORT)) + { + o_dramSparePort1Symbol = mss_x8dramSparePort1Index_to_symbol[l_dramSparePort1Index]; + } + else if ((l_dramWidth == mss_MemConfig::X4) && (l_dramSparePort1Index < MSS_X4_STEER_OPTIONS_PER_PORT1)) + { + o_dramSparePort1Symbol = mss_x4dramSparePort1Index_to_symbol[l_dramSparePort1Index]; + } + else + { + FAPI_ERR("Steer mux l_dramSparePort1Index out of range."); + + // TODO: Calling out FW high + // FFDC: MBA target + const fapi::Target & MBA = i_target; + // FFDC: DRAM width + uint8_t DRAM_WIDTH = l_dramWidth; + // FFDC: Capure i_rank; + uint8_t RANK = i_rank; + // FFDC: Capure i_muxType + uint8_t MUX_TYPE = i_muxType; + // FFDC: Capture steer mux + ecmdDataBufferBase & STEER_MUX = l_steerMux; + + // Create new log. + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_INVALID_STEER_MUX); + return l_rc; + } + + + //*************************************** + // Get l_eccSpareIndex + l_ecmd_rc |= l_steerMux.extractPreserve(&l_eccSpareIndex, 10, 5, 8-5); + if(l_ecmd_rc) + { + l_rc.setEcmdError(l_ecmd_rc); + return l_rc; + } + + // Get o_eccSpareSymbol if index in valid range + if (l_eccSpareIndex < MSS_X4_ECC_STEER_OPTIONS) + { + o_eccSpareSymbol = mss_eccSpareIndex_to_symbol[l_eccSpareIndex]; + } + else + { + FAPI_ERR("o_eccSpareSymbol out of range."); + + // TODO: Calling out FW high + // FFDC: MBA target + const fapi::Target & MBA = i_target; + // FFDC: DRAM width + uint8_t DRAM_WIDTH = l_dramWidth; + // FFDC: Capure i_rank; + uint8_t RANK = i_rank; + // FFDC: Capure i_muxType + uint8_t MUX_TYPE = i_muxType; + // FFDC: Capture steer mux + ecmdDataBufferBase & STEER_MUX = l_steerMux; + + // Create new log. + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_INVALID_STEER_MUX); + return l_rc; + } + + FAPI_INF("mss_get_steer_mux(): rank%d, port0 steer = %d, port1 steer = %d, ecc steer = %d", + i_rank, o_dramSparePort0Symbol, o_dramSparePort1Symbol, o_eccSpareSymbol ); + + return l_rc; + +} + + + + + + +//------------------------------------------------------------------------------ +// mss_put_steer_mux +//------------------------------------------------------------------------------ + +fapi::ReturnCode mss_put_steer_mux( const fapi::Target & i_target, + uint8_t i_rank, + mss_SteerMux::muxType i_muxType, + uint8_t i_steerType, + uint8_t i_symbol ) + + + +{ + FAPI_INF("ENTER mss_put_steer_mux()"); + + + fapi::ReturnCode l_rc; + uint32_t l_ecmd_rc = 0; + ecmdDataBufferBase l_steerMux(64); + ecmdDataBufferBase l_data(64); + uint8_t l_dramWidth = 0; + uint8_t l_dramSparePort0Index = 0; + uint8_t l_dramSparePort1Index = 0; + uint8_t l_eccSpareIndex = 0; + fapi::Target l_targetCentaur; + uint8_t l_mbaPosition = 0; + + // Get Centaur target for the given MBA + l_rc = fapiGetParentChip(i_target, l_targetCentaur); + if(l_rc) + { + FAPI_ERR("Error getting Centaur parent target for the given MBA"); + return l_rc; + } + + + // Get MBA position: 0 = mba01, 1 = mba23 + l_rc = FAPI_ATTR_GET(ATTR_CHIP_UNIT_POS, &i_target, l_mbaPosition); + if(l_rc) + { + FAPI_ERR("Error getting MBA position"); + return l_rc; + } + + // Get l_dramWidth + l_rc = FAPI_ATTR_GET(ATTR_EFF_DRAM_WIDTH, &i_target, l_dramWidth); + if(l_rc) + { + FAPI_ERR("Error getting DRAM width"); + return l_rc; + } + + + // Check for i_rank or i_muxType or i_steerType or i_symbol out of range + if ((i_rank>=8) || + !((i_muxType==mss_SteerMux::READ_MUX) || (i_muxType==mss_SteerMux::WRITE_MUX)) || + !((i_steerType == mss_SteerMux::DRAM_SPARE_PORT0) || (i_steerType == mss_SteerMux::DRAM_SPARE_PORT1) || (i_steerType == mss_SteerMux::ECC_SPARE)) || + (i_symbol >= 72)) + { + FAPI_ERR("i_rank or i_muxType or i_steerType or i_symbol input to mss_get_steer_mux out of range"); + // TODO: Calling out FW high + // FFDC: MBA target + const fapi::Target & MBA = i_target; + // FFDC: Capture i_rank; + uint8_t RANK = i_rank; + // FFDC: Capure i_muxType + uint8_t MUX_TYPE = i_muxType; + // FFDC: Capure i_steerType + uint8_t STEER_TYPE = i_steerType; + // FFDC: Capure i_symbol + uint8_t SYMBOL = i_symbol; + + // Create new log. + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_PUT_STEER_MUX_BAD_INPUT); + return l_rc; + } + + + // Read steer mux register for the given rank and mux type (read or write). + if (i_muxType == mss_SteerMux::READ_MUX) + { + // Read muxes are in the MBS + l_rc = fapiGetScom(l_targetCentaur, mss_readMuxRegs[i_rank][l_mbaPosition], l_steerMux); + if(l_rc) return l_rc; + } + else + { + // Write muxes are in the MBA + l_rc = fapiGetScom(i_target, mss_writeMuxRegs[i_rank], l_steerMux); + if(l_rc) return l_rc; + } + + + // Convert from i_symbol to l_dramSparePort0Index + if (i_steerType == mss_SteerMux::DRAM_SPARE_PORT0) + { + if (l_dramWidth == mss_MemConfig::X8) + { + l_dramSparePort0Index = MSS_X8_STEER_OPTIONS_PER_PORT; + for ( uint32_t i = 0; i < MSS_X8_STEER_OPTIONS_PER_PORT; i++ ) + { + if ( i_symbol == mss_x8dramSparePort0Index_to_symbol[i] ) + { + l_dramSparePort0Index = i; + break; + } + } + + if ( MSS_X8_STEER_OPTIONS_PER_PORT <= l_dramSparePort0Index ) + { + FAPI_ERR("No match for i_symbol = %d in mss_x8dramSparePort0Index_to_symbol[].", i_symbol); + + // TODO: Calling out FW high + // FFDC: MBA target + const fapi::Target & MBA = i_target; + // FFDC: DRAM width + uint8_t DRAM_WIDTH = l_dramWidth; + // FFDC: Capure i_rank; + uint8_t RANK = i_rank; + // FFDC: Capure i_muxType + uint8_t MUX_TYPE = i_muxType; + // FFDC: Capure i_steerType + uint8_t STEER_TYPE = i_steerType; + // FFDC: Capure i_symbol + uint8_t SYMBOL = i_symbol; + + // Create new log. + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_INVALID_SYMBOL_TO_STEER); + return l_rc; + } + } + + else if (l_dramWidth == mss_MemConfig::X4) + { + l_dramSparePort0Index = MSS_X4_STEER_OPTIONS_PER_PORT0; + for ( uint32_t i = 0; i < MSS_X4_STEER_OPTIONS_PER_PORT0; i++ ) + { + if ( i_symbol == mss_x4dramSparePort0Index_to_symbol[i] ) + { + l_dramSparePort0Index = i; + break; + } + } + + if ( MSS_X4_STEER_OPTIONS_PER_PORT0 <= l_dramSparePort0Index ) + { + FAPI_ERR("No match for i_symbol in mss_x4dramSparePort0Index_to_symbol[]."); + + // TODO: Calling out FW high + // FFDC: MBA target + const fapi::Target & MBA = i_target; + // FFDC: DRAM width + uint8_t DRAM_WIDTH = l_dramWidth; + // FFDC: Capure i_rank; + uint8_t RANK = i_rank; + // FFDC: Capure i_muxType + uint8_t MUX_TYPE = i_muxType; + // FFDC: Capure i_steerType + uint8_t STEER_TYPE = i_steerType; + // FFDC: Capure i_symbol + uint8_t SYMBOL = i_symbol; + + // Create new log. + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_INVALID_SYMBOL_TO_STEER); + return l_rc; + } + } + + l_ecmd_rc |= l_steerMux.insert( l_dramSparePort0Index, 0, 5, 8-5 ); + } + + + // Convert from i_symbol to l_dramSparePort1Index + if (i_steerType == mss_SteerMux::DRAM_SPARE_PORT1) + { + if (l_dramWidth == mss_MemConfig::X8) + { + l_dramSparePort1Index = MSS_X8_STEER_OPTIONS_PER_PORT; + for ( uint32_t i = 0; i < MSS_X8_STEER_OPTIONS_PER_PORT; i++ ) + { + if ( i_symbol == mss_x8dramSparePort1Index_to_symbol[i] ) + { + l_dramSparePort1Index = i; + break; + } + } + + if ( MSS_X8_STEER_OPTIONS_PER_PORT <= l_dramSparePort1Index ) + { + FAPI_ERR("No match for i_symbol in mss_x8dramSparePort1Index_to_symbol[]."); + + // TODO: Calling out FW high + // FFDC: MBA target + const fapi::Target & MBA = i_target; + // FFDC: DRAM width + uint8_t DRAM_WIDTH = l_dramWidth; + // FFDC: Capure i_rank; + uint8_t RANK = i_rank; + // FFDC: Capure i_muxType + uint8_t MUX_TYPE = i_muxType; + // FFDC: Capure i_steerType + uint8_t STEER_TYPE = i_steerType; + // FFDC: Capure i_symbol + uint8_t SYMBOL = i_symbol; + + // Create new log. + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_INVALID_SYMBOL_TO_STEER); + return l_rc; + } + } + + else if (l_dramWidth == mss_MemConfig::X4) + { + l_dramSparePort1Index = MSS_X4_STEER_OPTIONS_PER_PORT1; + for ( uint32_t i = 0; i < MSS_X4_STEER_OPTIONS_PER_PORT1; i++ ) + { + if ( i_symbol == mss_x4dramSparePort1Index_to_symbol[i] ) + { + l_dramSparePort1Index = i; + break; + } + } + + if ( MSS_X4_STEER_OPTIONS_PER_PORT1 <= l_dramSparePort1Index ) + { + FAPI_ERR("No match for i_symbol in mss_x4dramSparePort1Index_to_symbol[]."); + + // TODO: Calling out FW high + // FFDC: MBA target + const fapi::Target & MBA = i_target; + // FFDC: DRAM width + uint8_t DRAM_WIDTH = l_dramWidth; + // FFDC: Capure i_rank; + uint8_t RANK = i_rank; + // FFDC: Capure i_muxType + uint8_t MUX_TYPE = i_muxType; + // FFDC: Capure i_steerType + uint8_t STEER_TYPE = i_steerType; + // FFDC: Capure i_symbol + uint8_t SYMBOL = i_symbol; + + // Create new log. + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_INVALID_SYMBOL_TO_STEER); + return l_rc; + } + } + + l_ecmd_rc |= l_steerMux.insert( l_dramSparePort1Index, 5, 5, 8-5 ); + } + + + + // Convert from i_symbol to l_eccSpareIndex + if (i_steerType == mss_SteerMux::ECC_SPARE) + { + if (l_dramWidth == mss_MemConfig::X4) + { + l_eccSpareIndex = MSS_X4_ECC_STEER_OPTIONS; + for ( uint32_t i = 0; i < MSS_X4_ECC_STEER_OPTIONS; i++ ) + { + if ( i_symbol == mss_eccSpareIndex_to_symbol[i] ) + { + l_eccSpareIndex = i; + break; + } + } + + if ( MSS_X4_ECC_STEER_OPTIONS <= l_eccSpareIndex ) + { + FAPI_ERR("No match for i_symbol in mss_eccSpareIndex_to_symbol[]."); + + // TODO: Calling out FW high + // FFDC: MBA target + const fapi::Target & MBA = i_target; + // FFDC: DRAM width + uint8_t DRAM_WIDTH = l_dramWidth; + // FFDC: Capure i_rank; + uint8_t RANK = i_rank; + // FFDC: Capure i_muxType + uint8_t MUX_TYPE = i_muxType; + // FFDC: Capure i_steerType + uint8_t STEER_TYPE = i_steerType; + // FFDC: Capure i_symbol + uint8_t SYMBOL = i_symbol; + + // Create new log. + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_INVALID_SYMBOL_TO_STEER); + return l_rc; + } + } + else if (l_dramWidth == mss_MemConfig::X8) + { + FAPI_ERR("ECC_SPARE not valid with x8 mode."); + + // TODO: Calling out FW high + // FFDC: MBA target + const fapi::Target & MBA = i_target; + // FFDC: DRAM width + uint8_t DRAM_WIDTH = l_dramWidth; + // FFDC: Capure i_rank; + uint8_t RANK = i_rank; + // FFDC: Capure i_muxType + uint8_t MUX_TYPE = i_muxType; + // FFDC: Capure i_steerType + uint8_t STEER_TYPE = i_steerType; + // FFDC: Capure i_symbol + uint8_t SYMBOL = i_symbol; + + // Create new log. + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_NO_X8_ECC_SPARE); + return l_rc; + } + + l_ecmd_rc |= l_steerMux.insert( l_eccSpareIndex, 10, 5, 8-5 ); + } + + if(l_ecmd_rc) + { + l_rc.setEcmdError(l_ecmd_rc); + return l_rc; + } + + // Write the steer mux register for the given rank and mux + // type (read or write). + if (i_muxType == mss_SteerMux::READ_MUX) + { + // Read muxes are in the MBS + l_rc = fapiPutScom(l_targetCentaur, mss_readMuxRegs[i_rank][l_mbaPosition], l_steerMux); + if(l_rc) return l_rc; + } + else + { + // Write muxes are in the MBA + l_rc = fapiPutScom(i_target, mss_writeMuxRegs[i_rank], l_steerMux); + if(l_rc) return l_rc; + } + + + FAPI_INF("EXIT mss_put_steer_mux()"); + + return l_rc; + +} + + +//------------------------------------------------------------------------------ +// mss_check_steering +//------------------------------------------------------------------------------ + +fapi::ReturnCode mss_check_steering(const fapi::Target & i_target, + uint8_t i_rank, + uint8_t & o_dramSparePort0Symbol, + uint8_t & o_dramSparePort1Symbol, + uint8_t & o_eccSpareSymbol ) +{ + + // Get the read steer mux, with the assuption + // that the write mux will be the same. + return mss_get_steer_mux(i_target, + i_rank, + mss_SteerMux::READ_MUX, + o_dramSparePort0Symbol, + o_dramSparePort1Symbol, + o_eccSpareSymbol); +} + + +//------------------------------------------------------------------------------ +// mss_do_steering +//------------------------------------------------------------------------------ + +fapi::ReturnCode mss_do_steering(const fapi::Target & i_target, + uint8_t i_rank, + uint8_t i_symbol, + bool i_x4EccSpare) +{ + FAPI_INF("ENTER mss_do_steering()"); + + + fapi::ReturnCode l_rc; + uint8_t l_steerType = 0; // 0 = DRAM_SPARE_PORT0, Spare DRAM on port0 + // 1 = DRAM_SPARE_PORT1, Spare DRAM on port1 + // 2 = ECC_SPARE, ECC spare (used in x4 mode only) + + + // Check for i_rank or i_symbol out of range + if ((i_rank>=8) || (i_symbol>=72)) + { + FAPI_ERR("i_rank or i_symbol input to mss_do_steer out of range"); + // TODO: Calling out FW high + // FFDC: MBA target + const fapi::Target & MBA = i_target; + // FFDC: Capture i_rank; + uint8_t RANK = i_rank; + // FFDC: Capture i_symbol; + uint8_t SYMBOL = i_symbol; + // FFDC: Capture i_x4EccSpare + uint8_t X4ECCSPARE = i_x4EccSpare; + + // Create new log. + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_DO_STEER_INPUT_OUT_OF_RANGE); + return l_rc; + } + + //------------------------------------------------------ + // Determine l_steerType + //------------------------------------------------------ + if (i_x4EccSpare) + { + l_steerType = mss_SteerMux::ECC_SPARE; + } + else + { + // Symbols 71-40, 7-4 come from port0 + if (((i_symbol<=71)&&(i_symbol>=40)) || ((i_symbol<=7)&&(i_symbol>=4))) + { + l_steerType = mss_SteerMux::DRAM_SPARE_PORT0; + } + // Symbols 39-8, 3-0 come from port1 + else + { + l_steerType = mss_SteerMux::DRAM_SPARE_PORT1; + } + } + + //------------------------------------------------------ + // Update write mux + //------------------------------------------------------ + l_rc = mss_put_steer_mux( + + i_target, // MBA + i_rank, // Master rank: 0-7 + mss_SteerMux::WRITE_MUX,// write mux + l_steerType, // DRAM_SPARE_PORT0/DRAM_SPARE_PORT1/ECC_SPARE + i_symbol); // First symbol index of DRAM to steer around + + if (l_rc) + { + FAPI_ERR("Error updating write mux"); + return l_rc; + } + + //------------------------------------------------------ + // Wait for a periodic cal. + //------------------------------------------------------ + + // 250 ms delay for HW mode + const uint64_t HW_MODE_DELAY = 250000000; + + // 200000 sim cycle delay for SIM mode + const uint64_t SIM_MODE_DELAY = 200000; + + fapiDelay(HW_MODE_DELAY, SIM_MODE_DELAY); + + // TODO: Could be precise and find cal interval from: + // ATTR_EFF_ZQCAL_INTERVAL (in clocks... so still have to know freq) + // ATTR_EFF_MEMCAL_INTERVAL (in clocks... so still have to know freq) + + //------------------------------------------------------ + // Update read mux + //------------------------------------------------------ + l_rc = mss_put_steer_mux( + + i_target, // MBA + i_rank, // Master rank: 0-7 + mss_SteerMux::READ_MUX, // read mux + l_steerType, // DRAM_SPARE_PORT0/DRAM_SPARE_PORT1/ECC_SPARE + i_symbol); // First symbol index of DRAM to steer around + + if (l_rc) + { + FAPI_ERR("Error updating read mux"); + return l_rc; + + } + + FAPI_INF("EXIT mss_do_steering()"); + + return l_rc; +} + +//------------------------------------------------------------------------------ +// mss_restore_DRAM_repairs +//------------------------------------------------------------------------------ + + +fapi::ReturnCode mss_restore_DRAM_repairs( const fapi::Target & i_target, + uint8_t & o_repairs_applied, + uint8_t & o_repairs_exceeded) + +{ + + FAPI_INF("ENTER mss_restore_DRAM_repairs()"); + + + fapi::ReturnCode l_rc; + uint8_t l_dramWidth = 0; + uint8_t l_dqBitmap[DIMM_DQ_RANK_BITMAP_SIZE]; // 10 byte array of bad bits + ecmdDataBufferBase l_data(64); + uint8_t l_port=0; + uint8_t l_dimm=0; + uint8_t l_rank=0; + uint8_t l_byte=0; + uint8_t l_dq_pair_index = 0; + uint8_t l_bad_dq_pair_index = 0; + uint8_t l_bad_dq_pair_count=0; + uint8_t l_bad_dq_pair = 0xff; + uint8_t l_dq_pair_mask = 0xC0; + uint8_t l_byte_being_steered = 0xff; + uint8_t l_bad_symbol = MSS_INVALID_SYMBOL; + uint8_t l_symbol_mark = MSS_INVALID_SYMBOL; + uint8_t l_chip_mark = MSS_INVALID_SYMBOL; + bool l_spare_exists = false; + bool l_spare_used = false; + bool l_chip_mark_used = false; + bool l_symbol_mark_used = false; + uint8_t l_valid_dimms = 0; + uint8_t l_valid_dimm[2][2]; + + + // TODO: Fake this to show spares exist until attribute ready + // NO_SPARE = 0, LOW_NIBBLE = 1, HIGH_NIBBLE = 2, FULL_BYTE = 3 + uint8_t l_spare_dram[2][2][4]= { // Array defining if spare dram exits + {{3,3,3,3} , {3,3,3,3}}, + {{3,3,3,3} , {3,3,3,3}}}; + + + enum + { + MSS_REPAIRS_APPLIED = 1, + MSS_REPAIRS_EXCEEDED = 2, + }; + + uint8_t l_repair_status[2][2][4]={ + {{0,0,0,0} , {0,0,0,0}}, + {{0,0,0,0} , {0,0,0,0}}}; + + static const uint8_t l_repairs_applied_translation[8]={ + 0x80, //rank0 (maps to port0_dimm0, port1_dimm0) + 0x40, //rank1 (maps to port0_dimm0, port1_dimm0) + 0x20, //rank2 (maps to port0_dimm0, port1_dimm0) + 0x10, //rank3 (maps to port0_dimm0, port1_dimm0) + 0x08, //rank4 (maps to port0_dimm1, port1_dimm1) + 0x04, //rank5 (maps to port0_dimm1, port1_dimm1) + 0x02, //rank6 (maps to port0_dimm1, port1_dimm1) + 0x01}; //rank7 (maps to port0_dimm1, port1_dimm1) + + static const uint8_t l_repairs_exceeded_translation[2][2]={ + // dimm0 dimm1 + { 0x8, 0x4 }, // port0 + { 0x2, 0x1 }}; // port1 + + + + + // Start with no repairs applies and no repairs exceeded + o_repairs_applied = 0; + o_repairs_exceeded = 0; + + + // TODO: Fake this out for now since Anuwat is changing it. + // Get array attribute that defines if spare dram exits + // l_spare_dram[port][dimm][rank] + // NO_SPARE = 0, LOW_NIBBLE = 1, HIGH_NIBBLE = 2, FULL_BYTE = 3 + // NOTE: Typically will same value for whole Centaur. + //l_rc = FAPI_ATTR_GET(ATTR_EFF_DIMM_SPARE, &i_target, l_spare_dram); + //if(l_rc) + //{ + // FAPI_ERR("Error reading attribute to see if spare exists"); + // return l_rc; + //} + + // Get l_dramWidth + l_rc = FAPI_ATTR_GET(ATTR_EFF_DRAM_WIDTH, &i_target, l_dramWidth); + if(l_rc) + { + FAPI_ERR("Error getting DRAM width"); + return l_rc; + } + + // Find out which dimms are functional + l_rc = FAPI_ATTR_GET(ATTR_MSS_EFF_DIMM_FUNCTIONAL_VECTOR, &i_target, l_valid_dimms); + if (l_rc) + { + FAPI_ERR("Failed to get attribute: ATTR_MSS_EFF_DIMM_FUNCTIONAL_VECTOR"); + return l_rc; + } + l_valid_dimm[0][0] = (l_valid_dimms & 0x80); // port0, dimm0 + l_valid_dimm[0][1] = (l_valid_dimms & 0x40); // port0, dimm1 + l_valid_dimm[1][0] = (l_valid_dimms & 0x08); // port1, dimm0 + l_valid_dimm[1][1] = (l_valid_dimms & 0x04); // port1, dimm1 + + + // For each port in the given MBA:0,1 + for(l_port=0; l_port<DIMM_DQ_MAX_MBA_PORTS; l_port++ ) + { + // For each DIMM select on the given port:0,1 + for(l_dimm=0; l_dimm<DIMM_DQ_MAX_MBAPORT_DIMMS; l_dimm++ ) + { + if (l_valid_dimm[l_port][l_dimm]) + { + // For each rank select on the given DIMM select:0,1,2,3 + for(l_rank=0; l_rank<DIMM_DQ_MAX_DIMM_RANKS; l_rank++ ) + { + + + // Get the bad DQ Bitmap for l_port, l_dimm, l_rank + l_rc = dimmGetBadDqBitmap(i_target, + l_port, + l_dimm, + l_rank, + l_dqBitmap); + if (l_rc) + { + FAPI_ERR("Error from dimmGetBadDqBitmap"); + return l_rc; + } + + // x8 ECC + // x8 bit chip mark, x2 bit symbol mark, spare x8 DRAM if CDIMM + if (l_dramWidth == mss_MemConfig::X8) + { + + // Determine if spare x8 DRAM exists + l_spare_exists = l_spare_dram[l_port][l_dimm][l_rank] == mss_MemConfig::FULL_BYTE; + + // Start with spare not used + l_spare_used = false; + l_byte_being_steered = MSS_INVALID_SYMBOL; + + // Read mark store + l_rc = mss_get_mark_store( + + i_target, // MBA + 4*l_dimm + l_rank, // Master rank: 0-7 + l_symbol_mark, // MSS_INVALID_SYMBOL if no symbol mark + l_chip_mark ); // MSS_INVALID_SYMBOL if no chip mark + + if (l_rc) + { + FAPI_ERR("Error reading markstore"); + return l_rc; + } + + // Check if chip mark used (may have been used on other port) + l_chip_mark_used = l_chip_mark != MSS_INVALID_SYMBOL; + + // Check if symbol mark used (may have been used on other port) + l_symbol_mark_used = l_symbol_mark != MSS_INVALID_SYMBOL; + + // Initialize to no bad dq pair found yet + l_bad_dq_pair = 0xff; + + // For each byte 0-9, where 9 is the spare + for(l_byte=0; l_byte<DIMM_DQ_RANK_BITMAP_SIZE; l_byte++ ) + { + if ((l_byte == 9) && !l_spare_exists) + { + // Don't look at byte 9 if spare doesn't exist + break; + } + + if (l_dqBitmap[l_byte] == 0) + { + // Don't bother analyzing if byte is clean + continue; + } + + // Mask initialized to look at first dq pair in byte + l_dq_pair_mask = 0xC0; + + // Start with no bad dq pairs counted for this byte + l_bad_dq_pair_count = 0; + + // For each of the 4 dq pairs in the byte + for(l_dq_pair_index=0; l_dq_pair_index<4; l_dq_pair_index++ ) + { + + // If any bad bits in this dq pair + if (l_dqBitmap[l_byte] & l_dq_pair_mask) + { + // Increment bad symbol count + l_bad_dq_pair_count++; + + // Record bad dq pair - just most recent if multiple bad + l_bad_dq_pair_index = l_dq_pair_index; + l_bad_dq_pair = 8*l_byte + 2*l_bad_dq_pair_index; + } + + // Shift mask to next symbol + l_dq_pair_mask = l_dq_pair_mask >> 2; + } + + // If spare is bad but not used, not valid to try repair + if ( l_spare_exists && (l_byte==9) && (l_bad_dq_pair_count > 0) && !l_spare_used) + { + FAPI_ERR("WARNING: port=%d, dimm=%d, rank=%d, l_dqBitmap[%d] = %02x, Bad unused spare - no valid repair", + l_port, l_dimm, l_rank, l_byte, l_dqBitmap[l_byte]); + + break; + } + + // If more than one dq pair is bad + if(l_bad_dq_pair_count > 1) + { + + // If spare x8 DRAM exists and not used yet, + if (l_spare_exists && !l_spare_used) + { + l_bad_symbol = mss_centaurDQ_to_symbol(8*l_byte,l_port) - 3; + + // Update read mux + l_rc = mss_put_steer_mux( + + i_target, // MBA + 4*l_dimm + l_rank, // Master rank: 0-7 + mss_SteerMux::READ_MUX, // read mux + l_port, // l_port: 0,1 + l_bad_symbol); // First symbol index of byte to steer + + if (l_rc) + { + FAPI_ERR("Error updating read mux"); + return l_rc; + + } + + // Update write mux + l_rc = mss_put_steer_mux( + + i_target, // MBA + 4*l_dimm + l_rank, // Master rank: 0-7 + mss_SteerMux::WRITE_MUX,// write mux + l_port, // l_port: 0,1 + l_bad_symbol); // First symbol index of byte to steer + + if (l_rc) + { + FAPI_ERR("Error updating write mux"); + return l_rc; + } + + // Spare now used on this port,dimm,rank + l_spare_used = true; + + // Remember which byte is being steered + // so we know where to apply chip or symbol mark + // if spare turns out to be bad + l_byte_being_steered = l_byte; + + // Update which rank 0-7 has had repairs applied + o_repairs_applied |= l_repairs_applied_translation[4*l_dimm + l_rank]; + + l_repair_status[l_port][l_dimm][l_rank]=MSS_REPAIRS_APPLIED; + + // If port1 repairs applied and port0 had repairs exceeded, say port1 repairs exceeded too + if ((l_repair_status[1][l_dimm][l_rank] == MSS_REPAIRS_APPLIED) && (l_repair_status[0][l_dimm][l_rank] == MSS_REPAIRS_EXCEEDED)) + { + o_repairs_exceeded |= l_repairs_exceeded_translation[1][l_dimm]; + } + + FAPI_ERR("WARNING: port=%d, dimm=%d, rank=%d, l_dqBitmap[%d] = %02x, dq %d-%d, symbols %d-%d, FIXED CHIP WITH X8 STEER", + l_port, l_dimm, l_rank, l_byte, l_dqBitmap[l_byte], 8*l_byte, 8*l_byte+7,l_bad_symbol, l_bad_symbol+3 ); + + + } + + // Else if chip mark not used yet, update mark store with chip mark + else if (!l_chip_mark_used) + { + // NOTE: Have to do a read/modify/write so we + // only update chip mark, and don't overwrite + // symbol mark. + + // Read mark store + l_rc = mss_get_mark_store( + + i_target, // MBA + 4*l_dimm + l_rank, // Master rank: 0-7 + l_symbol_mark, // Reading this just to write it back + l_chip_mark ); // Expecting MSS_INVALID_SYMBOL since no chip mark + + if (l_rc) + { + FAPI_ERR("Error reading markstore"); + return l_rc; + } + + + // Special case: + // If this is a bad spare byte we are analyzing + // the chip mark goes on the byte being steered + if (l_byte==9) + { + l_chip_mark = mss_centaurDQ_to_symbol(8*l_byte_being_steered,l_port) - 3; + FAPI_ERR("WARNING: Bad spare so chip mark goes on l_byte_being_steered = %d", l_byte_being_steered); + } + + else + { + l_chip_mark = mss_centaurDQ_to_symbol(8*l_byte,l_port) - 3; + } + + // Write mark store + l_rc = mss_put_mark_store( + + i_target, // MBA + 4*l_dimm + l_rank, // Master rank: 0-7 + l_symbol_mark, // Writting back exactly what we read + l_chip_mark ); // First symbol index of byte getting chip mark + + if (l_rc) + { + FAPI_ERR("Error updating markstore"); + return l_rc; + } + + // Chip mark now used on this rank + l_chip_mark_used = true; + + // Update which rank 0-7 has had repairs applied + o_repairs_applied |= l_repairs_applied_translation[4*l_dimm + l_rank]; + + l_repair_status[l_port][l_dimm][l_rank]=MSS_REPAIRS_APPLIED; + + // If port1 repairs applied and port0 had repairs exceeded, say port1 repairs exceeded too + if ((l_repair_status[1][l_dimm][l_rank] == MSS_REPAIRS_APPLIED) && (l_repair_status[0][l_dimm][l_rank] == MSS_REPAIRS_EXCEEDED)) + { + o_repairs_exceeded |= l_repairs_exceeded_translation[1][l_dimm]; + } + + FAPI_ERR("WARNING: port=%d, dimm=%d, rank=%d, l_dqBitmap[%d] = %02x, dq %d-%d, symbols %d-%d, FIXED CHIP WITH X8 CHIP MARK", + l_port, l_dimm, l_rank, l_byte, l_dqBitmap[l_byte], 8*l_byte, 8*l_byte+7,l_chip_mark, l_chip_mark+3 ); + + } + + // Else, more bad bits than we can repair so update o_repairs_exceeded + else + { + o_repairs_exceeded |= l_repairs_exceeded_translation[l_port][l_dimm]; + + l_repair_status[l_port][l_dimm][l_rank]=MSS_REPAIRS_EXCEEDED; + + // If port1 repairs exceeded and port0 had a repair, say port0 repairs exceeded too + if ((l_repair_status[1][l_dimm][l_rank] == MSS_REPAIRS_EXCEEDED) && (l_repair_status[0][l_dimm][l_rank] == MSS_REPAIRS_APPLIED)) + { + o_repairs_exceeded |= l_repairs_exceeded_translation[0][l_dimm]; + } + + FAPI_ERR("WARNING: port=%d, dimm=%d, rank=%d, l_dqBitmap[%d] = %02x, dq %d-%d, REPAIRS EXCEEDED", + l_port, l_dimm, l_rank, l_byte, l_dqBitmap[l_byte], 8*l_byte, 8*l_byte+7); + + + // Break out of loop on bytes + break; + } + } // End If bad symbol count > 1 + + + //Else if bad symbol count = 1 + else if(l_bad_dq_pair_count == 1) + { + // If symbol mark not used yet, update mark store with symbol mark + if (!l_symbol_mark_used) + { + + // NOTE: Have to do a read/modify/write so we + // only update symbol mark, and don't overwrite + // chip mark. + + // Read mark store + l_rc = mss_get_mark_store( + + i_target, // MBA + 4*l_dimm + l_rank, // Master rank: 0-7 + l_symbol_mark, // Expecting MSS_INVALID_SYMBOL since no symbol mark + l_chip_mark ); // Reading this just to write it back + + if (l_rc) + { + FAPI_ERR("Error reading markstore"); + return l_rc; + } + + // Special case: + // If this is a bad spare byte we are analying + // the symbol mark goes on the byte being steered + if (l_byte==9) + { + l_symbol_mark = mss_centaurDQ_to_symbol(8*l_byte_being_steered + 2*l_bad_dq_pair_index,l_port); + FAPI_ERR("WARNING: Bad spare so symbol mark goes on l_byte_being_steered = %d", l_byte_being_steered); + } + + else + { + l_symbol_mark = mss_centaurDQ_to_symbol(8*l_byte + 2*l_bad_dq_pair_index,l_port); + } + + + // Update mark store + l_rc = mss_put_mark_store( + + i_target, // MBA + 4*l_dimm + l_rank, // Master rank: 0-7 + l_symbol_mark, // Single bad symbol found on this byte + l_chip_mark ); // Writting back exactly what we read + + if (l_rc) + { + FAPI_ERR("Error updating markstore"); + return l_rc; + } + + // Symbol mark now used on this rank + l_symbol_mark_used = true; + + // Update which rank 0-7 has had repairs applied + o_repairs_applied |= l_repairs_applied_translation[4*l_dimm + l_rank]; + + l_repair_status[l_port][l_dimm][l_rank]=MSS_REPAIRS_APPLIED; + + // If port1 repairs applied and port0 had repairs exceeded, say port1 repairs exceeded too + if ((l_repair_status[1][l_dimm][l_rank] == MSS_REPAIRS_APPLIED) && (l_repair_status[0][l_dimm][l_rank] == MSS_REPAIRS_EXCEEDED)) + { + o_repairs_exceeded |= l_repairs_exceeded_translation[1][l_dimm]; + } + + FAPI_ERR("WARNING: port=%d, dimm=%d, rank=%d, l_dqBitmap[%d] = %02x, dq %d-%d, symbol %d, FIXED SYMBOL WITH X2 SYMBOL MARK", + l_port, l_dimm, l_rank, l_byte, l_dqBitmap[l_byte], + 8*l_byte + 2*l_bad_dq_pair_index, 8*l_byte + 2*l_bad_dq_pair_index + 1, + l_symbol_mark ); + + } + + + // Else if spare x8 DRAM exists and not used yet, update steer mux + else if (l_spare_exists && !l_spare_used) + { + + l_bad_symbol = mss_centaurDQ_to_symbol(8*l_byte,l_port) - 3; + + // Update read mux + l_rc = mss_put_steer_mux( + + i_target, // MBA + 4*l_dimm + l_rank, // Master rank: 0-7 + mss_SteerMux::READ_MUX, // read mux + l_port, // l_port: 0,1 + l_bad_symbol ); // First symbol index of byte to steer + + if (l_rc) + { + FAPI_ERR("Error updating read mux"); + return l_rc; + + } + + // Update write mux + l_rc = mss_put_steer_mux( + + i_target, // MBA + 4*l_dimm + l_rank, // Master rank: 0-7 + mss_SteerMux::WRITE_MUX,// write mux + l_port, // l_port: 0,1 + l_bad_symbol ); // First symbol index of byte to steer + + if (l_rc) + { + FAPI_ERR("Error updating write mux"); + return l_rc; + } + + // Spare now used on this port,dimm,rank + l_spare_used = true; + + // Remember which byte is being steered + // so we where to apply chip or symbol mark + // if spare turns out to be bad + l_byte_being_steered = l_byte; + + // Update which rank 0-7 has had repairs applied + o_repairs_applied |= l_repairs_applied_translation[4*l_dimm + l_rank]; + + l_repair_status[l_port][l_dimm][l_rank]=MSS_REPAIRS_APPLIED; + + // If port1 repairs applied and port0 had repairs exceeded, say port1 repairs exceeded too + if ((l_repair_status[1][l_dimm][l_rank] == MSS_REPAIRS_APPLIED) && (l_repair_status[0][l_dimm][l_rank] == MSS_REPAIRS_EXCEEDED)) + { + o_repairs_exceeded |= l_repairs_exceeded_translation[1][l_dimm]; + } + + FAPI_ERR("WARNING: port=%d, dimm=%d, rank=%d, l_dqBitmap[%d] = %02x, dq %d-%d, symbols %d-%d, FIXED SYMBOL WITH X8 STEER", + l_port, l_dimm, l_rank, l_byte, l_dqBitmap[l_byte], + 8*l_byte + 2*l_bad_dq_pair_index, 8*l_byte + 2*l_bad_dq_pair_index + 1, + l_bad_symbol, + l_bad_symbol + 3); + + } + + // Else if chip mark not used yet, update mark store with chip mark + else if (!l_chip_mark_used) + { + + // NOTE: Have to do a read/modify/write so we + // only update chip mark, and don't overwrite + // symbol mark. + + // Read mark store + l_rc = mss_get_mark_store( + + i_target, // MBA + 4*l_dimm + l_rank, // Master rank: 0-7 + l_symbol_mark, // Reading this just to write it back + l_chip_mark ); // Expecting MSS_INVALID_SYMBOL since no chip mark + + if (l_rc) + { + FAPI_ERR("Error reading markstore"); + return l_rc; + } + + + // Special case: + // If this is a bad spare byte we are analying + // the chip mark goes on the byte being steered + if (l_byte==9) + { + l_chip_mark = mss_centaurDQ_to_symbol(8*l_byte_being_steered,l_port) - 3; + FAPI_ERR("WARNING: Bad spare so chip mark goes on l_byte_being_steered = %d", l_byte_being_steered); + } + + else + { + l_chip_mark = mss_centaurDQ_to_symbol(8*l_byte,l_port) - 3; + } + + // Update mark store + l_rc = mss_put_mark_store( + + i_target, // MBA + 4*l_dimm + l_rank, // Master rank: 0-7 + l_symbol_mark, // Writting back exactly what we read + l_chip_mark ); // First symbol index of byte getting chip mark + + if (l_rc) + { + FAPI_ERR("Error updating markstore"); + return l_rc; + } + + // Chip mark now used on this rank + l_chip_mark_used = true; + + // Update which rank 0-7 has had repairs applied + o_repairs_applied |= l_repairs_applied_translation[4*l_dimm + l_rank]; + + l_repair_status[l_port][l_dimm][l_rank]=MSS_REPAIRS_APPLIED; + + // If port1 repairs applied and port0 had repairs exceeded, say port1 repairs exceeded too + if ((l_repair_status[1][l_dimm][l_rank] == MSS_REPAIRS_APPLIED) && (l_repair_status[0][l_dimm][l_rank] == MSS_REPAIRS_EXCEEDED)) + { + o_repairs_exceeded |= l_repairs_exceeded_translation[1][l_dimm]; + } + + FAPI_ERR("WARNING: port=%d, dimm=%d, rank=%d, l_dqBitmap[%d] = %02x, dq %d-%d, symbols %d-%d, FIXED SYMBOL WITH X8 CHIP MARK", + l_port, l_dimm, l_rank, l_byte, l_dqBitmap[l_byte], + 8*l_byte + 2*l_bad_dq_pair_index, 8*l_byte + 2*l_bad_dq_pair_index + 1, + l_chip_mark, + l_chip_mark + 3); + + } + + + // Else, more bad bits than we can repair so update o_repairs_exceeded + else + { + + o_repairs_exceeded |= l_repairs_exceeded_translation[l_port][l_dimm]; + + l_repair_status[l_port][l_dimm][l_rank]=MSS_REPAIRS_EXCEEDED; + + // If port1 repairs exceeded and port0 had a repair, say port0 repairs exceeded too + if ((l_repair_status[1][l_dimm][l_rank] == MSS_REPAIRS_EXCEEDED) && (l_repair_status[0][l_dimm][l_rank] == MSS_REPAIRS_APPLIED)) + { + o_repairs_exceeded |= l_repairs_exceeded_translation[0][l_dimm]; + } + + FAPI_ERR("WARNING: port=%d, dimm=%d, rank=%d, l_dqBitmap[%d] = %02x, dq %d-%d, REPAIRS EXCEEDED", + l_port, l_dimm, l_rank, l_byte, l_dqBitmap[l_byte], + 8*l_byte + 2*l_bad_dq_pair_index, 8*l_byte + 2*l_bad_dq_pair_index + 1); + + // Break out of loop on bytes + break; + } + + } // End If bad symbol count = 1 + + } // End For each byte 0-9, where 9 is the spare + + } // End x8 ECC + + // x4 ECC + // x4 chip mark, x4 ECC steer, spare x4 DRAM if CDIMM + else if (l_dramWidth == mss_MemConfig::X4) + { + } // End x4 ECC + + } // End loop on rank + } // End if valid dimm + } // End loop on dimm + } // End loop on port + + + + + + + FAPI_INF("o_repairs_applied = %02x\n", o_repairs_applied); + FAPI_INF("o_repairs_exceeded = %02x\n", o_repairs_exceeded); + + FAPI_INF("EXIT mss_restore_DRAM_repairs()"); + + return l_rc; + +} + + +//------------------------------------------------------------------------------ +// mss_centaurDQ_to_symbol +//------------------------------------------------------------------------------ + +uint8_t mss_centaurDQ_to_symbol( uint8_t i_dq, uint8_t i_port ) +{ + + uint8_t o_symbol = MSS_INVALID_SYMBOL; + + if ( 64 <= i_dq ) // DQs 64 - 71 + { + o_symbol = (71 - i_dq) / 2; // symbols 0 - 3 + if ( 0 == i_port ) o_symbol += 4; // symbols 4 - 7 + } + else // DQs 0 - 63 + { + o_symbol = (71 - i_dq + 8) / 2; // symbols 8 - 39 + if ( 0 == i_port ) o_symbol += 32; // symbols 40 - 71 + } + + return o_symbol; +} + +//------------------------------------------------------------------------------ +// mss_IPL_UE_isolation +//------------------------------------------------------------------------------ + +fapi::ReturnCode mss_IPL_UE_isolation( const fapi::Target & i_target, + uint8_t i_rank, + uint8_t (&o_bad_bits)[2][10]) + +{ + FAPI_INF("ENTER mss_IPL_UE_isolation()"); + + fapi::ReturnCode l_rc; + uint32_t l_ecmd_rc = 0; + + static const uint32_t maintBufferReadDataRegs[2][2][8]={ + + // UE trap 0: + // Port0 beat double word + {{MAINT0_MBA_MAINT_BUFF0_DATA0_0x03010655, // 0 DW0 + MAINT0_MBA_MAINT_BUFF2_DATA0_0x03010675, // 1 DW2 + MAINT0_MBA_MAINT_BUFF0_DATA1_0x03010656, // 2 DW4 + MAINT0_MBA_MAINT_BUFF2_DATA1_0x03010676, // 3 DW6 + MAINT0_MBA_MAINT_BUFF0_DATA2_0x03010657, // 4 DW8 + MAINT0_MBA_MAINT_BUFF2_DATA2_0x03010677, // 5 DW10 + MAINT0_MBA_MAINT_BUFF0_DATA3_0x03010658, // 6 DW12 + MAINT0_MBA_MAINT_BUFF2_DATA3_0x03010678},// 7 DW14 + + // Port1 + {MAINT0_MBA_MAINT_BUFF1_DATA0_0x03010665, // 0 DW1 + MAINT0_MBA_MAINT_BUFF3_DATA0_0x03010685, // 1 DW3 + MAINT0_MBA_MAINT_BUFF1_DATA1_0x03010666, // 2 DW5 + MAINT0_MBA_MAINT_BUFF3_DATA1_0x03010686, // 3 DW7 + MAINT0_MBA_MAINT_BUFF1_DATA2_0x03010667, // 4 DW9 + MAINT0_MBA_MAINT_BUFF3_DATA2_0x03010687, // 5 DW11 + MAINT0_MBA_MAINT_BUFF1_DATA3_0x03010668, // 6 DW13 + MAINT0_MBA_MAINT_BUFF3_DATA3_0x03010688}},//7 DW15 + + // UE trap 1: + // Port0 + {{MAINT0_MBA_MAINT_BUFF0_DATA4_0x03010659, // 0 DW0 + MAINT0_MBA_MAINT_BUFF2_DATA4_0x03010679, // 1 DW2 + MAINT0_MBA_MAINT_BUFF0_DATA5_0x0301065a, // 2 DW4 + MAINT0_MBA_MAINT_BUFF2_DATA5_0x0301067a, // 3 DW6 + MAINT0_MBA_MAINT_BUFF0_DATA6_0x0301065b, // 4 DW8 + MAINT0_MBA_MAINT_BUFF2_DATA6_0x0301067b, // 5 DW10 + MAINT0_MBA_MAINT_BUFF0_DATA7_0x0301065c, // 6 DW12 + MAINT0_MBA_MAINT_BUFF2_DATA7_0x0301067c},// 7 DW14 + + // Port1 + {MAINT0_MBA_MAINT_BUFF1_DATA4_0x03010669, // 0 DW1 + MAINT0_MBA_MAINT_BUFF3_DATA4_0x03010689, // 1 DW3 + MAINT0_MBA_MAINT_BUFF1_DATA5_0x0301066a, // 2 DW5 + MAINT0_MBA_MAINT_BUFF3_DATA5_0x0301068a, // 3 DW7 + MAINT0_MBA_MAINT_BUFF1_DATA6_0x0301066b, // 4 DW9 + MAINT0_MBA_MAINT_BUFF3_DATA6_0x0301068b, // 5 DW11 + MAINT0_MBA_MAINT_BUFF1_DATA7_0x0301066c, // 6 DW13 + MAINT0_MBA_MAINT_BUFF3_DATA7_0x0301068c}}};//7 DW15 + + + static const uint32_t maintBufferRead65thByteRegs[2][4]={ + // UE trap 0 + {MAINT0_MBA_MAINT_BUFF_65TH_BYTE_64B_ECC0_0x03010695, + MAINT0_MBA_MAINT_BUFF_65TH_BYTE_64B_ECC1_0x03010696, + MAINT0_MBA_MAINT_BUFF_65TH_BYTE_64B_ECC2_0x03010697, + MAINT0_MBA_MAINT_BUFF_65TH_BYTE_64B_ECC3_0x03010698}, + // UE trap 1 + {MAINT0_MBA_MAINT_BUFF_65TH_BYTE_64B_ECC4_0x03010699, + MAINT0_MBA_MAINT_BUFF_65TH_BYTE_64B_ECC5_0x0301069a, + MAINT0_MBA_MAINT_BUFF_65TH_BYTE_64B_ECC6_0x0301069b, + MAINT0_MBA_MAINT_BUFF_65TH_BYTE_64B_ECC7_0x0301069c}}; + + + uint8_t l_UE_trap = 0; // 0,1, since UE can be in 1st or 2nd half of buffer + uint8_t l_port = 0; // 0,1 + uint8_t l_beat = 0; // 0-7 + uint8_t l_byte = 0; // 0-9 + uint8_t l_loop = 0; + ecmdDataBufferBase l_data(64); + ecmdDataBufferBase l_UE_trap0_signature(64); + ecmdDataBufferBase l_UE_trap1_signature(64); + ecmdDataBufferBase l_mbmmr(64); + ecmdDataBufferBase l_mbmct(64); + ecmdDataBufferBase l_mbstr(64); + uint8_t l_initPattern = 0; + uint8_t l_cmd_type = 0; + fapi::Target l_targetCentaur; + uint8_t l_mbaPosition = 0; + uint32_t l_tmp_data_diff[2]; + uint8_t l_tag_MDI = 0; + uint8_t l_tmp_65th_byte_diff = 0; + ecmdDataBufferBase l_diff(64); + uint32_t l_ECC = 0; + uint32_t l_tmp_ECC_diff = 0; + ecmdDataBufferBase l_ECC_diff(32); + uint8_t l_ECC_c6_c5_c4_01 = 0; + uint8_t l_ECC_c6_c5_c4_23 = 0; + uint8_t l_ECC_c3_c2_c1_c0_01 = 0; + uint8_t l_ECC_c3_c2_c1_c0_23 = 0; + uint8_t l_dramSparePort0Symbol = MSS_INVALID_SYMBOL; + uint8_t l_dramSparePort1Symbol = MSS_INVALID_SYMBOL; + uint8_t l_eccSpareSymbol = MSS_INVALID_SYMBOL; + + //---------------------------------------------------- + // Initialize o_bad_bits + //---------------------------------------------------- + + for(l_port=0; l_port<2; l_port++ ) + { + for(l_byte=0; l_byte<10; l_byte++ ) + { + o_bad_bits[l_port][l_byte] = 0; + } + } + + + //---------------------------------------------------- + // Get the expected pattern (stored in mbmmr reg) + //---------------------------------------------------- + + // Get Centaur target for the given MBA + l_rc = fapiGetParentChip(i_target, l_targetCentaur); + if(l_rc) + { + FAPI_ERR("Error getting Centaur parent target for the given MBA"); + return l_rc; + } + + // Get MBA position: 0 = mba01, 1 = mba23 + l_rc = FAPI_ATTR_GET(ATTR_CHIP_UNIT_POS, &i_target, l_mbaPosition); + if(l_rc) + { + FAPI_ERR("Error getting MBA position"); + return l_rc; + } + + // MBMMR[4:7] contains the pattern index + l_rc = fapiGetScom(l_targetCentaur, mss_mbmmr[l_mbaPosition], l_mbmmr); + if(l_rc) return l_rc; + l_ecmd_rc |= l_mbmmr.extractPreserve(&l_initPattern, 4, 4, 8-4); + if(l_ecmd_rc) + { + l_rc.setEcmdError(l_ecmd_rc); + return l_rc; + } + + // MBMCT[0:4] contains the cmd type + l_rc = fapiGetScom(i_target, MBA01_MBMCTQ_0x0301060A, l_mbmct); + if(l_rc) return l_rc; + l_ecmd_rc |= l_mbmct.extractPreserve(&l_cmd_type, 0, 5, 8-5); + if(l_ecmd_rc) + { + l_rc.setEcmdError(l_ecmd_rc); + return l_rc; + } + + // No isolation if cmd is timebased steer cleanup + if (l_cmd_type == 2) + { + FAPI_ERR("WARNING: rank%d maint UE during steer cleanup - no bad bit isolation possible.", i_rank); + return l_rc; + } + + // No isolation if pattern is random + if (l_initPattern == 8) + { + FAPI_ERR("WARNING: rank%d maint UE with random pattern - no bad bit isolation possible.", i_rank); + return l_rc; + } + + + FAPI_INF("Expected pattern%d = 0x%.8X 0x%.8X",l_initPattern, + mss_maintBufferData[l_initPattern][0][0], + mss_maintBufferData[l_initPattern][0][1]); + + //---------------------------------------------------- + // Figure out which half of the buffer has the UE... + // Remember we had to first load the buffers with + // a hex signatue, and whichever gets overwritten + // has a UE trapped + //---------------------------------------------------- + l_rc = fapiGetScom(i_target, MAINT0_MBA_MAINT_BUFF0_DATA0_0x03010655, l_UE_trap0_signature); + if(l_rc) return l_rc; + + l_rc = fapiGetScom(i_target, MAINT0_MBA_MAINT_BUFF0_DATA4_0x03010659, l_UE_trap1_signature); + if(l_rc) return l_rc; + + // UE may be trapped in both halves of the buffer, + // but we will only use one. + if ((l_UE_trap0_signature.getWord(0) != 0xFACEB00C) && + (l_UE_trap0_signature.getWord(0) != 0xD15C0DAD)) + { + FAPI_INF("UE trapped in 1st half of maint buffer"); + l_UE_trap = 0; + } + else if ((l_UE_trap1_signature.getWord(0) != 0xFACEB00C) && + (l_UE_trap1_signature.getWord(0) != 0xD15C0DAD)) + { + FAPI_INF("UE trapped in 2nd half of maint buffer"); + l_UE_trap = 1; + } + else + { + FAPI_ERR("IPL UE trapping didn't work."); + + // Read for FFDC: MBSTR[59]: UE trap enable bit + l_rc = fapiGetScom(l_targetCentaur, mss_mbstr[l_mbaPosition], l_mbstr); + if(l_rc) return l_rc; + + + // Calling out MBA target high, deconfig, gard + const fapi::Target & MBA = i_target; + // FFDC: Capture UE trap contents + ecmdDataBufferBase & UE_TRAP0 = l_UE_trap0_signature; + ecmdDataBufferBase & UE_TRAP1 = l_UE_trap1_signature; + // FFDC: MBMCT[0:4] contains the cmd type + ecmdDataBufferBase & MBMCT = l_mbmct; + // FFDC: MBMMR[4:7] contains the pattern index + ecmdDataBufferBase & MBMMR = l_mbmmr; + // FFDC: MBSTR[59]: UE trap enable bit + ecmdDataBufferBase & MBSTR = l_mbstr; + + // Create new log + FAPI_SET_HWP_ERROR(l_rc, RC_MSS_MAINT_NO_UE_TRAP); + + return l_rc; + } + + + + //---------------------------------------------------- + // DATA: Do XOR of expected and actual data to find stuck bits + //---------------------------------------------------- + + for(l_port=0; l_port<2; l_port++ ) + { + l_tmp_data_diff[0] = 0; + l_tmp_data_diff[1] = 0; + + FAPI_INF("port%d", l_port); + for(l_beat=0; l_beat<8; l_beat++ ) + { + + l_rc = fapiGetScom(i_target, maintBufferReadDataRegs[l_UE_trap][l_port][l_beat], l_data); + if(l_rc) return l_rc; + FAPI_INF("Actual data, beat%d: 0x%.8X 0x%.8X", l_beat, l_data.getWord(0), l_data.getWord(1)); + + FAPI_INF("Expected pattern%d = 0x%.8X 0x%.8X",l_initPattern, + mss_maintBufferData[l_initPattern][l_port*8 + l_beat][0], + mss_maintBufferData[l_initPattern][l_port*8 + l_beat][1]); + + // DO XOR of actual and expected data, and OR the result together for all 8 beats + l_tmp_data_diff[0] |= l_data.getWord(0) ^ mss_maintBufferData[l_initPattern][l_port*8 + l_beat][0]; + l_tmp_data_diff[1] |= l_data.getWord(1) ^ mss_maintBufferData[l_initPattern][l_port*8 + l_beat][1]; + + FAPI_INF("***************************************** l_tmp_diff: 0x%.8X 0x%.8X", l_tmp_data_diff[0], l_tmp_data_diff[1]); + } + + // Put l_tmp_diff into a ecmdDataBufferBase to make it easier + // to get into o_bad_bits + l_ecmd_rc |= l_diff.insert(l_tmp_data_diff[0], 0, 32, 0); + l_ecmd_rc |= l_diff.insert(l_tmp_data_diff[1], 32, 32, 0); + if(l_ecmd_rc) + { + l_rc.setEcmdError(l_ecmd_rc); + return l_rc; + } + + for(l_byte=0; l_byte<8; l_byte++ ) + { + l_ecmd_rc |= l_diff.extractPreserve(&o_bad_bits[l_port][l_byte], 8*l_byte, 8, 0); + } + if(l_ecmd_rc) + { + l_rc.setEcmdError(l_ecmd_rc); + return l_rc; + } + + } // End loop on ports + + + + //---------------------------------------------------- + // 65th byte: Do XOR of expected and actual 65th byte to find stuck bits + //---------------------------------------------------- + + for(l_loop=0; l_loop<4; l_loop++ ) + { + l_tag_MDI = 0; + l_tmp_65th_byte_diff = 0; + + l_rc = fapiGetScom(i_target, maintBufferRead65thByteRegs[l_UE_trap][l_loop], l_data); + if(l_rc) return l_rc; + + // Grab bit 0 = Checkbit0_1 + // Grab bit 1 = Tag0_2 + // Grab bit 2 = Tag1_3 + // Grab bit 3 = MDI + l_ecmd_rc |= l_data.extractPreserve(&l_tag_MDI, 0, 4, 0); + if(l_ecmd_rc) + { + l_rc.setEcmdError(l_ecmd_rc); + return l_rc; + } + + FAPI_INF("Actual: bit0 (Checkbit0_1), bit1(Tag0_2), bit2(Tag1_3), bit3(MDI) = 0x%.2X", l_tag_MDI); + + FAPI_INF("Expected: bit0 (Checkbit0_1), bit1(Tag0_2), bit2(Tag1_3), bit3(MDI) = 0x%.2X", mss_65thByte[l_initPattern][l_loop]); + + // DO XOR of actual and expected data + l_tmp_65th_byte_diff = l_tag_MDI ^ mss_65thByte[l_initPattern][l_loop]; + FAPI_INF("***************************************** l_tmp_65th_byte_diff: 0x%.2X", l_tmp_65th_byte_diff); + + + // Check for mismatch in bit 0: Checkbit0_1 + if (l_tmp_65th_byte_diff & 0x80) + { + // Checkbit0_1 maps to port0 bit 64, which is on byte8 + o_bad_bits[0][8] |= 0x80; + } + + // Check for mismatch in bit 1: Tag0_2 + if (l_tmp_65th_byte_diff & 0x40) + { + // Tag0_2 maps to port0 bit 65, which is on byte8 + o_bad_bits[0][8] |= 0x40; + } + + // Check for mismatch in bit 2: Tag1_3 + if (l_tmp_65th_byte_diff & 0x20) + { + // Tag1_3 maps to port0 bit 64, which is on byte8 + o_bad_bits[0][8] |= 0x80; + } + + // Check for mismatch in bit 3: MDI + if (l_tmp_65th_byte_diff & 0x10) + { + // MDI maps to port0 bit 65, which is on byte8 + o_bad_bits[0][8] |= 0x40; + } + } // End loops through trapped 65th byte info + + + //---------------------------------------------------- + // ECC: Do XOR of expected and actual ECC bits to find stuck bits + //---------------------------------------------------- + + for(l_loop=0; l_loop<4; l_loop++ ) + { + l_ECC = 0; + + l_rc = fapiGetScom(i_target, maintBufferRead65thByteRegs[l_UE_trap][l_loop], l_data); + if(l_rc) return l_rc; + + // Grab bits 4:15 = ECC_c6_c5_c4, and bits 16:31 = ECC_c3_c2_c1_c0 + l_ecmd_rc |= l_data.extractPreserve(&l_ECC, 4, 28, 4); + if(l_ecmd_rc) + { + l_rc.setEcmdError(l_ecmd_rc); + return l_rc; + } + + FAPI_INF("Actual: ECC = 0x%.8X", l_ECC); + + FAPI_INF("Expected: ECC = 0x%.8X", mss_ECC[l_initPattern][l_loop]); + + // DO XOR of actual and expected data + l_tmp_ECC_diff |= l_ECC ^ mss_ECC[l_initPattern][l_loop]; + FAPI_INF("***************************************** l_tmp_ECC_diff: 0x%.8X", l_tmp_ECC_diff); + } + + // Put l_tmp_ECC_diff into a ecmdDataBufferBase to make it easier + // to get into o_bad_bits + l_ecmd_rc |= l_ECC_diff.insert(l_tmp_ECC_diff, 0, 32, 0); + if(l_ecmd_rc) + { + l_rc.setEcmdError(l_ecmd_rc); + return l_rc; + } + + l_ecmd_rc |= l_ECC_diff.extractPreserve(&l_ECC_c6_c5_c4_01, 4, 6, 8-6); + l_ecmd_rc |= l_ECC_diff.extractPreserve(&l_ECC_c6_c5_c4_23, 10, 6, 8-6); + l_ecmd_rc |= l_ECC_diff.extractPreserve(&l_ECC_c3_c2_c1_c0_01, 16, 8, 0); + l_ecmd_rc |= l_ECC_diff.extractPreserve(&l_ECC_c3_c2_c1_c0_23, 24, 8, 0); + if(l_ecmd_rc) + { + l_rc.setEcmdError(l_ecmd_rc); + return l_rc; + } + + // The 6 bits of ECC_c6_c5_c4 maps to byte8 on port0 + o_bad_bits[0][8] |= l_ECC_c6_c5_c4_01 | l_ECC_c6_c5_c4_23; + // The 8 bits of ECC_c3_c2_c1_c0 maps to byte8 byte on port1 + o_bad_bits[1][8] |= l_ECC_c3_c2_c1_c0_01 | l_ECC_c3_c2_c1_c0_23; + + + //---------------------------------------------------- + // Spare: Mark byte9 bad if bad bits found in position being steered + //---------------------------------------------------- + + // READ steer mux, which gets me a symbol for port0 and port1 + l_rc = mss_check_steering(i_target, + i_rank, + l_dramSparePort0Symbol, + l_dramSparePort1Symbol, + l_eccSpareSymbol); + if(l_rc) return l_rc; + + // If steering on port0 + if ( l_dramSparePort0Symbol != 0xff) + { + // Find the byte being steered + l_byte = mss_chip_mark_to_centaurDQ[l_dramSparePort0Symbol/4][0]/8; + + // If that byte has any bad bits in it, copy them to byte9, + if (o_bad_bits[0][l_byte]) + { + o_bad_bits[0][9] = o_bad_bits[0][l_byte]; + + // Clear byte being steered, since it did not contribute to UE + o_bad_bits[0][l_byte] = 0; + } + } + + // If steering on port1 + if ( l_dramSparePort1Symbol != 0xff) + { + // Find the byte being steered + l_byte = mss_chip_mark_to_centaurDQ[l_dramSparePort1Symbol/4][0]/8; + + // If that byte has any bad bits in it, copy them to byte9, + if (o_bad_bits[1][l_byte]) + { + o_bad_bits[1][9] = o_bad_bits[1][l_byte]; + + // Clear byte being steered, since it did not contribute to UE + o_bad_bits[1][l_byte] = 0; + } + } + + //---------------------------------------------------- + // Show results + //---------------------------------------------------- + + FAPI_ERR("WARNING: IPL UE isolation results for rank = %d.", i_rank); + FAPI_ERR("WARNING: Expected pattern = 0x%.8X", mss_maintBufferData[l_initPattern][0][0]); + for(l_port=0; l_port<2; l_port++ ) + { + for(l_byte=0; l_byte<10; l_byte++ ) + { + FAPI_ERR("WARNING: o_bad_bits[port%d][byte%d] = %02x", + l_port, l_byte, o_bad_bits[l_port][l_byte]); + } + } + + + FAPI_INF("EXIT mss_IPL_UE_isolation()"); + + return l_rc; + + +} + + diff --git a/src/usr/hwpf/hwp/utility_procedures/utils.mk b/src/usr/hwpf/hwp/utility_procedures/utils.mk index 9d074d396..88432057d 100644 --- a/src/usr/hwpf/hwp/utility_procedures/utils.mk +++ b/src/usr/hwpf/hwp/utility_procedures/utils.mk @@ -5,7 +5,7 @@ # # IBM CONFIDENTIAL # -# COPYRIGHT International Business Machines Corp. 2012 +# COPYRIGHT International Business Machines Corp. 2012,2013 # # p1 # @@ -21,8 +21,11 @@ # # IBM_PROLOG_END_TAG EXTRAINCDIR += ${ROOTPATH}/src/usr/hwpf/hwp/utility_procedures +EXTRAINCDIR += ${ROOTPATH}/src/include/usr/hwpf/hwp +EXTRAINCDIR += ${ROOTPATH}/src/include/usr/hwpf/hwp/utility_procedures +EXTRAINCDIR += ${ROOTPATH}/usr/hwpf/hwp/include VPATH += utility_procedures -OBJS += mss_unmask_errors.o +OBJS += mss_unmask_errors.o mss_maint_cmds.o |