summaryrefslogtreecommitdiffstats
path: root/src/import/chips/p9/procedures/hwp/memory/lib/fir/check.H
blob: 6bf1553173644d0939d8c0ac5f3358b9c21254a3 (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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/fir/check.H $   */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] 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 check.H
/// @brief Subroutines for checking MSS FIR
///
// *HWP HWP Owner: Andre Marin <aamarin@us.ibm.com>
// *HWP HWP Backup: Marc Gollub <gollub@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 3
// *HWP Consumed by: FSP:HB

#ifndef _MSS_CHECK_FIR_H_
#define _MSS_CHECK_FIR_H_

#include <fapi2.H>
#include <generic/memory/lib/utils/scom.H>
#include <generic/memory/lib/utils/mss_generic_check.H>

namespace mss
{

namespace check
{

///
/// @brief Check FIR bits during PHY reset
/// @note For DDRPHYFIR and some MBACALFIR errors, up to and including phy reset, need to
/// handle within the phy reset procedure, since we may get errors from a 'non-functional'
/// magic port, which PRD can't analyze.
/// @tparam T the fapi2::TargetType which hold the FIR bits
/// @param[in] i_target the fapi2::Target
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS iff ok
///
template< fapi2::TargetType T >
fapi2::ReturnCode during_phy_reset( const fapi2::Target<T>& i_target );

///
/// @brief Check FIR bits during draminit training
/// @tparam T the fapi2::TargetType which hold the FIR bits
/// @param[in] i_target the dimm that was trained
/// @note We check for fir errors after training each rank
/// to see if there was a problem with the engine
/// FFDC errors return from this will be handle similar to other training errors
/// Logged if it affects less than a nibble and a bit.
/// Reported if it affects more than that
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS iff ok
///
template< fapi2::TargetType T >
fapi2::ReturnCode during_draminit_training( const fapi2::Target<T>& i_target );

///
/// @brief Checks whether any of the PLL unlock values are set
/// @param[in] i_local_fir - the overall FIR register
/// @param[in] i_perv_fir - the pervasive PLL FIR
/// @param[in] i_mc_fir - the memory controller FIR
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS iff ok
///
bool pll_unlock( const fapi2::buffer<uint64_t>& i_local_fir,
                 const fapi2::buffer<uint64_t>& i_perv_fir,
                 const fapi2::buffer<uint64_t>& i_mc_fir );

///
/// @brief Checks whether any PLL FIRs have been set on a target
/// @param[in] i_target - the target on which to operate
/// @param[in,out] io_rc - the return code for the function
/// @param[out] o_fir_error - true iff a FIR was hit
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS iff ok
///
fapi2::ReturnCode pll_fir( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target,
                           fapi2::ReturnCode& io_rc,
                           bool& o_fir_error );

///
/// @brief Checks whether the passed in FIRs have any un-masked errors set
/// @tparam T the fapi2::TargetType which hold the FIR bits
/// @param[in] i_target - the target on which to operate
/// @param[in] i_fir_regs - FIR register and mask register
/// @param[out] o_fir_error - true iff a FIR was hit
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS iff ok
///
template< fapi2::TargetType T >
inline fapi2::ReturnCode fir_with_mask( const fapi2::Target<T>& i_target,
                                        const std::pair<uint64_t, uint64_t>& i_fir_regs,
                                        bool& o_fir_error )
{
    // Temporary variables to make the code a bit more readable
    const auto FIR_REG = i_fir_regs.first;
    const auto FIR_MASK = i_fir_regs.second;

    fapi2::buffer<uint64_t> l_fir;
    fapi2::buffer<uint64_t> l_fir_mask;

    // Read the registers
    FAPI_TRY(mss::getScom(i_target, FIR_REG, l_fir));
    FAPI_TRY(mss::getScom(i_target, FIR_MASK, l_fir_mask));


    // The mask register will need to be inverted as a 0 in the mask register means the FIR is legit
    // A bitwise and works the opposite way
    l_fir_mask.invert();

    // If we have any unmasked bit, set that we have a FIR error and exit out with success
    // Note: we want to set success here as PRD will find the FIR as "new" and retrigger the procedure this way
    o_fir_error = ((l_fir & l_fir_mask) != 0);

    // And print the information for debuggability
    FAPI_INF("%s %s on reg 0x%016lx value 0x%016lx and mask 0x%016lx value 0x%016lx", mss::c_str(i_target),
             o_fir_error ? "has FIR's set" : "has no FIR's set", FIR_REG, l_fir, FIR_MASK, l_fir_mask.invert());

fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief Checks whether a FIR or unlocked PLL could be the root cause of another failure
/// @tparam T the fapi2::TargetType which hold the FIR bits
/// @param[in] i_target - the target on which to operate
/// @param[in,out] io_rc - the return code for the function
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS iff ok
/// @note This is a helper function to enable unit testing
///
template< fapi2::TargetType T >
fapi2::ReturnCode hostboot_fir_or_pll_fail( const fapi2::Target<T>& i_target, fapi2::ReturnCode& io_rc)
{
    // We didn't have an error, so return success
    if(io_rc == fapi2::FAPI2_RC_SUCCESS)
    {
        FAPI_INF("%s has a good return code, returning success", mss::c_str(i_target));
        return fapi2::FAPI2_RC_SUCCESS;
    }

    fapi2::ReturnCode l_fircheck_scom_err(fapi2::FAPI2_RC_SUCCESS);
    bool l_fir_error = false;

    FAPI_ERR("%s has a bad return code, time to check some firs!", mss::c_str(i_target));

    l_fircheck_scom_err = bad_fir_bits<mss::mc_type::NIMBUS>(i_target, io_rc, l_fir_error);

    FAPI_ERR("%s took a fail. FIR was %s", mss::c_str(i_target),
             l_fir_error ? "set - returning FIR RC" : "unset - returning inputted RC");

    // If we had a FIR error, log the original error and return success
    // PRD will handle the original error
    if(l_fir_error)
    {
        fapi2::current_err = fapi2::FAPI2_RC_SUCCESS;
    }
    else
    {
        fapi2::current_err = io_rc;
    }

    return fapi2::current_err;
}

///
/// @brief Checks whether a FIR or unlocked PLL could be the root cause of another failure, if a check fir boolean is passed in
/// @tparam T the fapi2::TargetType which hold the FIR bits
/// @param[in] i_target - the target on which to operate
/// @param[in,out] io_rc - the return code for the function
/// @param[in] i_check_fir - true IFF the FIR needs to be checked - defaults to true
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS iff ok
///
template< fapi2::TargetType T >
fapi2::ReturnCode fir_or_pll_fail( const fapi2::Target<T>& i_target,
                                   fapi2::ReturnCode& io_rc,
                                   const bool i_check_fir = true)
{
#ifdef __HOSTBOOT_MODULE

    fapi2::ReturnCode l_rc(io_rc);

    // If need be, check the FIR below
    if(i_check_fir)
    {
        // Handle any issues according to PRD FIR scheme, as a FIR could have caused this issue
        l_rc = hostboot_fir_or_pll_fail(i_target, l_rc);
    }

    return l_rc;

#else
    return io_rc;
#endif
}

}
}
#endif
OpenPOWER on IntegriCloud