summaryrefslogtreecommitdiffstats
path: root/src/sbefw/sbescom.C
blob: 634c88687080a8de9fc7d0b290e66728394ae1e2 (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
/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/sbefw/sbescom.C $                                         */
/*                                                                        */
/* OpenPOWER sbe Project                                                  */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016                             */
/* [+] 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                                                     */

#include <stdint.h>
#include "sbe_sp_intf.H"
#include "sbetrace.H"
#include "plat_hw_access.H"
#include "plat_target.H"
#include "sbescom.H"

using namespace fapi2;
/**
 * @brief Indirect SCOM Status
 */
union IndirectScom_t
{
    uint64_t data64;
    struct
    {
        uint64_t :12;        //0:11
        uint64_t addr:20;    //12:31
        uint64_t done:1;     //32
        uint64_t piberr:3;   //33:35
        uint64_t userstat:4; //36:39
        uint64_t :8;         //40:47
        uint64_t data:16;    //48:63
    };

};

// Wait time slice to check indirect scom status register
static const uint32_t SBE_INDIRECT_SCOM_WAIT_TIME_NS = 10000;
// Indirect scom timeout
static const uint32_t MAX_INDSCOM_TIMEOUT_NS = 100000; //0.1 ns

static const uint64_t DIRECT_SCOM_ADDR_MASK = 0x8000000000000000;
static const uint64_t INDIRECT_SCOM_NEW_ADDR_MASK = 0x9000000000000000;

// Scom types
enum sbeScomType
{
    SBE_SCOM_TYPE_DIRECT = 0,      // Direct scom
    SBE_SCOM_TYPE_INDIRECT1 = 1,  // Indirect scom. Old form
    SBE_SCOM_TYPE_INDIRECT_2 = 2,  // Indirect scom. New form
};

uint32_t checkIndirectAndDoScom( const bool i_isRead,
                                 const uint64_t i_addr,
                                 uint64_t & io_data,
                                 sbeResponseFfdc_t *const o_ffdc)
{

    #define SBE_FUNC " checkIndirectAndDoScom "
    uint32_t l_rc = SBE_SEC_OPERATION_SUCCESSFUL;
    uint32_t elapsedIndScomTimeNs = 0;
    uint64_t tempBuffer = io_data;
    sbeScomType scomType = SBE_SCOM_TYPE_DIRECT;
    ReturnCode fapiRc = FAPI2_RC_SUCCESS;
    do
    {
        // If the indirect scom bit is 0, then doing a regular scom
        if( (i_addr & DIRECT_SCOM_ADDR_MASK) == 0)
        {
            plat_target_handle_t l_hndl;
            SBE_INFO(SBE_FUNC "Performing Direct scom.");
            if( i_isRead )
            {
                fapiRc = getscom_abs_wrap (&l_hndl, (uint32_t)i_addr,
                                              & io_data);
            }
            else
            {
                fapiRc = putscom_abs_wrap (&l_hndl, (uint32_t)i_addr,
                                              io_data);
            }
            break;
        }
        // We are performing an indirect scom.
        if( ( i_addr & INDIRECT_SCOM_NEW_ADDR_MASK ) ==
                                        INDIRECT_SCOM_NEW_ADDR_MASK )
        {
            scomType = SBE_SCOM_TYPE_INDIRECT_2;
            if( i_isRead )
            {
                // Not allowed write on new format.
                SBE_ERROR(SBE_FUNC "Read not allowed in new form");
                l_rc = SBE_SEC_INVALID_ADDRESS_PASSED;
                break;
            }
            // Zero out the indirect address location.. leave the 52bits of data
            // Get the 12bit indirect scom address
            // OR in the 20bit indirect address
            tempBuffer = ( tempBuffer & 0x000FFFFFFFFFFFFF ) |
                                    ( ( i_addr & 0x00000FFF00000000) << 20 );
        }
        else
        {
            scomType = SBE_SCOM_TYPE_INDIRECT1;
            // Zero out the indirect address location.. leave the 16bits of data
            // Get the 20bit indirect scom address
            // OR in the 20bit indirect address
            tempBuffer = ( tempBuffer & 0x000000000000FFFF) |
                                    ( i_addr & 0x000FFFFF00000000 );
        }

        SBE_INFO(SBE_FUNC "Performing Indirect scom. Type :%u", scomType);

        // zero out the indirect address from the buffer..
        // bit 0-31 - indirect area..
        // bit 32 - always 0
        // bit 33-47 - bcast/chipletID/port
        // bit 48-63 - local addr
        uint64_t tempAddr = i_addr & 0x000000007FFFFFFF;
        plat_target_handle_t l_hndl;

        // If we are doing a read. We need to do a write first..
        if( i_isRead)
        {
            // turn the read bit on.
            tempBuffer = tempBuffer | 0x8000000000000000;
        }
        else //write
        {
            // Turn the read bit off.
            tempBuffer = tempBuffer & 0x7FFFFFFFFFFFFFFF;

        } // end of write

        // perform write before the read with the new
        // IO_buffer with the imbedded indirect scom addr.
        fapiRc = putscom_abs_wrap (&l_hndl, tempAddr, tempBuffer);

        if( ( fapiRc != FAPI2_RC_SUCCESS ) ||
                ( scomType == SBE_SCOM_TYPE_INDIRECT_2 ))
        {
            break;
        }

        // Need to check loop on read until we see done, error,
        //  or we timeout
        IndirectScom_t scomout;
        do
        {
            // Now perform the op requested using the passed in
            // IO_Buffer to pass the read data back to caller.
            fapiRc = getscom_abs_wrap (&l_hndl, tempAddr, &(scomout.data64));

            if( fapiRc != FAPI2_RC_SUCCESS) break;
            // if bit 32 is on indicating a complete bit
            //  or we saw an error, then we're done
            if (scomout.piberr)
            {

                SBE_ERROR(SBE_FUNC "pib error reading status register");
                break;
            }
            if (scomout.done )
            {
                io_data = scomout.data;
                break;
            }

            pk_sleep(PK_NANOSECONDS(SBE_INDIRECT_SCOM_WAIT_TIME_NS));
            elapsedIndScomTimeNs += SBE_INDIRECT_SCOM_WAIT_TIME_NS;

        }while ( elapsedIndScomTimeNs <= MAX_INDSCOM_TIMEOUT_NS);

        if( fapiRc != FAPI2_RC_SUCCESS ) break;
        if( ! scomout.done)
        {
            SBE_ERROR(SBE_FUNC "Indirect scom timeout.");
            l_rc = SBE_SEC_HW_OP_TIMEOUT;
            break;
        }

    }while(0);

    if  (fapiRc != FAPI2_RC_SUCCESS)
    {
        l_rc = SBE_SEC_PCB_PIB_ERR;
        if(o_ffdc) o_ffdc->setRc(fapiRc);
    }

    SBE_DEBUG(SBE_FUNC "fapiRc:%u l_rc:0x%08X", fapiRc, l_rc);
    return l_rc;
}

OpenPOWER on IntegriCloud