summaryrefslogtreecommitdiffstats
path: root/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/sim.C
blob: 933676c48bdfd78c5f7f7513559ce619f2dadf21 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/mcbist/sim.C $  */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2017                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file mcbist/sim.C
/// @brief MCBIST/memdiags functions for when we're in simulation mode
///
// *HWP HWP Owner: Stephen Glancy <sglancy@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 3
// *HWP Consumed by: FSP:HB

#include <fapi2.H>

#include <lib/dimm/rank.H>
#include <lib/mcbist/address.H>
#include <lib/mcbist/mcbist.H>
#include <lib/mcbist/patterns.H>
#include <lib/mcbist/sim.H>
#include <lib/utils/count_dimm.H>

using fapi2::TARGET_TYPE_MCBIST;
using fapi2::TARGET_TYPE_MCA;
using fapi2::TARGET_TYPE_SYSTEM;
using fapi2::FAPI2_RC_SUCCESS;

namespace mss
{

namespace mcbist
{

namespace sim
{

///
/// @brief Perform a sim version of initializing memory
/// @param[in] i_target MCBIST
/// @param[in] i_pattern an index representing a pattern to use to initize memory (defaults to 0)
/// @return FAPI2_RC_SUCCESS iff ok
///
template<>
fapi2::ReturnCode sf_init( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target,
                           const uint64_t i_pattern )
{
    FAPI_INF("Start sim init");

    // If we're running in the simulator, we want to only touch the addresses which training touched

    for (const auto& p : i_target.getChildren<TARGET_TYPE_MCA>())
    {
        std::vector<uint64_t> l_pr;
        mss::mcbist::program<TARGET_TYPE_MCBIST> l_program;

        mss::mcbist::address l_start;
        mss::mcbist::address l_end;

        size_t l_rank_address_pair = 0;

        // No point in bothering if we don't have any DIMM
        if (mss::count_dimm(p) == 0)
        {
            FAPI_INF("No DIMM on %s, not running sf_init", mss::c_str(p));
            continue;
        }

        // In sim we know a few things ...
        // Get the primary ranks for this port. We know there can only be 4, and we know we only trained the primary
        // ranks. Therefore, we only need to clean up the primary ranks. And because there's 4 max, we can do it
        // all using the 4 address range registers of tne MCBIST (broadcast currently not considered.)
        // So we can write 0's to those to get their ECC fixed up.
        FAPI_TRY( mss::rank::primary_ranks(p, l_pr) );
        fapi2::Assert( l_pr.size() <= mss::MAX_RANK_PER_DIMM );

        for (auto r = l_pr.begin(); r != l_pr.end(); ++l_rank_address_pair, ++r)
        {
            FAPI_INF("sim init %s, rank %d", mss::c_str(p), *r);

            // Setup l_start to represent this rank, and then make the end address from that.
            l_start.set_master_rank(*r);

            // Set C3 bit to get an entire cache line
            l_start.get_sim_end_address(l_end);

            // By default we're in maint address mode, not address counting mode. So we give it a start and end, and ignore
            // anything invalid - that's what maint address mode is all about
            mss::mcbist::config_address_range(i_target, l_start, l_end, l_rank_address_pair);

            // Write
            {
                // Run in ECC mode, 64B writes (superfast mode)

                mss::mcbist::subtest_t<TARGET_TYPE_MCBIST> l_fw_subtest =
                    mss::mcbist::write_subtest<TARGET_TYPE_MCBIST>();

                l_fw_subtest.enable_port(mss::relative_pos<TARGET_TYPE_MCBIST>(p));
                l_fw_subtest.change_addr_sel(l_rank_address_pair);
                l_fw_subtest.enable_dimm(mss::rank::get_dimm_from_rank(*r));
                l_program.iv_subtests.push_back(l_fw_subtest);
                FAPI_DBG("adding superfast write for %s rank %d (dimm %d)", mss::c_str(p), *r, mss::rank::get_dimm_from_rank(*r));
            }

            // Read - we do a read here as verification can use this as a tool as we do the write and then the read.
            // If we failed to write properly the read would thow ECC errors. Just a write (which the real hardware would
            // do) doesn't catch that. This takes longer, but it's not terribly long in any event.
            {
                // Run in ECC mode, 64B writes (superfast mode)
                mss::mcbist::subtest_t<TARGET_TYPE_MCBIST> l_fr_subtest =
                    mss::mcbist::read_subtest<TARGET_TYPE_MCBIST>();

                l_fr_subtest.enable_port(mss::relative_pos<TARGET_TYPE_MCBIST>(p));
                l_fr_subtest.change_addr_sel(l_rank_address_pair);
                l_fr_subtest.enable_dimm(mss::rank::get_dimm_from_rank(*r));
                l_program.iv_subtests.push_back(l_fr_subtest);
                FAPI_DBG("adding superfast read for %s rank %d (dimm %d)", mss::c_str(p), *r, mss::rank::get_dimm_from_rank(*r));
            }
        }

        // Write pattern
        FAPI_TRY( mss::mcbist::load_pattern(i_target, i_pattern) );

        // Setup the sim polling based on a heuristic <cough>guess</cough>
        // Looks like ~400ck per address for a write/read program on the sim-dimm, and add a long number of polls
        // On real hardware wait 100ms and then start polling for another 5s
        l_program.iv_poll.iv_initial_sim_delay = mss::cycles_to_simcycles(((l_end - l_start) * l_pr.size()) * 800);
        l_program.iv_poll.iv_initial_delay = 100 * mss::DELAY_1MS;
        l_program.iv_poll.iv_sim_delay = 100000;
        l_program.iv_poll.iv_delay = 10 * mss::DELAY_1MS;
        l_program.iv_poll.iv_poll_count = 500;

        // Just one port for now. Per Shelton we need to set this in maint address mode
        // even tho we specify the port/dimm in the subtest.
        fapi2::buffer<uint8_t> l_port;
        l_port.setBit(mss::relative_pos<TARGET_TYPE_MCBIST>(p));
        l_program.select_ports(l_port >> 4);

        // Kick it off, wait for a result
        FAPI_TRY( mss::mcbist::execute(i_target, l_program) );
    }

fapi_try_exit:
    FAPI_INF("End sim init");
    return fapi2::current_err;
}

} // namespace sim

} // namespace mcbist

} // namespace mss
OpenPOWER on IntegriCloud