summaryrefslogtreecommitdiffstats
path: root/src/occ_405/amec/amec_sensors_fw.c
blob: daf9fd789ddd986a122682fe5afc9452080be30c (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
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/occ_405/amec/amec_sensors_fw.c $                          */
/*                                                                        */
/* OpenPOWER OnChipController Project                                     */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2011,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                                                     */

/******************************************************************************/
/* Includes                                                                   */
/******************************************************************************/
#include <occ_common.h>
#include <ssx.h>
#include <errl.h>               // Error logging
#include "sensor.h"
#include "rtls.h"
#include "occ_sys_config.h"
#include "occ_service_codes.h"  // for SSX_GENERIC_FAILURE
#include "dcom.h"
#include "proc_data.h"
#include "amec_smh.h"
#include "amec_slave_smh.h"
#include <trac.h>
#include "amec_sys.h"
#include "sensor_enum.h"
#include "amec_service_codes.h"
#include <amec_sensors_fw.h>
#include "gpe_register_addresses.h"
#include "gpe_firmware_registers.h"

/******************************************************************************/
/* Globals                                                                    */
/******************************************************************************/
extern bool G_24x7_disabled;

//*************************************************************************
// Code
//*************************************************************************

// Function Specification
//
// Name: amec_slv_update_smh_sensors
//
// Description: Update FW Sensors with Amec Slave Timings.
//
// End Function Specification
void amec_slv_update_smh_sensors(int i_smh_state, uint32_t i_duration)
{
    // Update the duration in the fw timing table
    G_fw_timing.amess_state = i_smh_state;
    G_fw_timing.amess_dur   = i_duration;
}


// Function Specification
//
// Name: amec_slv_update_gpe_sensors
//
// Description: Update FW Sensors with GPE Engine Timings. Called from
//              callback on GPE routine completion.
//
// End Function Specification
void amec_slv_update_gpe_sensors(uint8_t i_gpe_engine)
{
    // Update the duration in the fw timing table
    G_fw_timing.gpe_dur[i_gpe_engine] = DURATION_IN_US_UNTIL_NOW_FROM(G_fw_timing.rtl_start_gpe[i_gpe_engine]);
}

// Function Specification
//
// Name: task_gpe_timings
//
// Description: Kick off tasks to time GPEs
//
// Thread: RealTime Loop
//
// End Function Specification
#define MAX_CONSEC_TRACE 4
void task_gpe_timings(task_t * i_task)
{
    errlHndl_t l_err                = NULL;
    int rc                          = 0;
    int rc2                         = 0;
    static uint8_t L_idleTicks      = 0;
    static uint8_t L_busyTicks      = 0;
    static bool L_first_call        = TRUE;
    bool l_gpe0_idle                = TRUE;
    bool l_gpe1_idle                = TRUE;

    static uint8_t L_consec_trace_count[2] = {0};
    gpe_gpenxiramdbg_t xsr_sprg0 = {0};
    gpe_gpenxiramedr_t ir_edr = {0};
    gpe_gpenxidbgpro_t iar_xsr = {0};

    // ------------------------------------------------------
    // Kick off GPE programs to track WorstCase time in GPE
    // and update the sensors.
    // ------------------------------------------------------
    if(NULL != G_fw_timing.gpe0_timing_request)
    {
        //Check if GPE0 was able to complete the last GPE job within 1 tick
        l_gpe0_idle = async_request_is_idle(&G_fw_timing.gpe0_timing_request->request);

        if(l_gpe0_idle)
        {
            //reset the consecutive trace count
            L_consec_trace_count[0] = 0;

            //Now check if successful too.
            if( async_request_completed(&(G_fw_timing.gpe0_timing_request->request)) )
            {
                // GPEtickdur0 = duration of last tick's PORE-GPE0 duration
                sensor_update( AMECSENSOR_PTR(GPEtickdur0), G_fw_timing.gpe_dur[0]);
            }
            //This case is expected on the first call of the function.
            //After that, this should not happen.
            else if(!L_first_call)
            {
                //Note: FFDC for this case is gathered by each task
                //responsible for a GPE job.
                TRAC_INFO("GPE0 task idle but GPE0 task did not complete");
            }

            // Schedule the GPE Routines that will run and update the worst
            // case timings (via callback) after they complete.  These GPE
            // routines are the last GPE routines added to the queue
            // during the RTL tick.
            G_fw_timing.rtl_start_gpe[0] = G_fw_timing.rtl_start;
            rc  = gpe_request_schedule(G_fw_timing.gpe0_timing_request);
        }
        else
        {
            // Reset will eventually be requested due to not having power measurement
            // data after X ticks, but add some additional FFDC to the trace that
            // will tell us what GPE job is currently executing.
            INCREMENT_ERR_HISTORY(ERRH_GPE0_NOT_IDLE);

            if(L_consec_trace_count[0] < MAX_CONSEC_TRACE)
            {
               xsr_sprg0.fields.xsr = in32(GPE_GPE0XIXSR);
               xsr_sprg0.fields.sprg0 = in32(GPE_GPE0XISPRG0);
               ir_edr.fields.edr = in32(GPE_GPE0XIEDR);
               ir_edr.fields.ir = in32(GPE_GPE0XIIR);
               iar_xsr.fields.iar = in32(GPE_GPE0XIIAR);
               TRAC_ERR("GPE0 programs did not complete within one tick. "
                         "XSR[0x%08x]  IAR[0x%08x] IR[0x%08x] EDR[0x%08x] SPRG0[0x%08X]",
                         xsr_sprg0.fields.xsr, iar_xsr.fields.iar,
                         ir_edr.fields.ir, ir_edr.fields.edr, xsr_sprg0.fields.sprg0);
                L_consec_trace_count[0]++;
            }
        }

    }
    if(NULL != G_fw_timing.gpe1_timing_request)
    {
        //Check if GPE1 was able to complete the last GPE job within 1 tick
        l_gpe1_idle = async_request_is_idle(&G_fw_timing.gpe1_timing_request->request);

        if(l_gpe1_idle)
        {
            //reset the consecutive trace count
            L_consec_trace_count[1] = 0;

            //Now check if successful too.
            if( async_request_completed(&(G_fw_timing.gpe1_timing_request->request)) )
            {
                // GPEtickdur1 = duration of last tick's PORE-GPE1 duration
                sensor_update( AMECSENSOR_PTR(GPEtickdur1), G_fw_timing.gpe_dur[1]);
            }
            //This case is expected on the first call of the function.
            //After that, this should not happen.
            else if(!L_first_call)
            {
                //Note: FFDC for this case is gathered by each task
                //responsible for a GPE job.
                TRAC_INFO("GPE1 task idle but GPE1 task did not complete");
            }

            // Schedule the GPE Routines that will run and update the worst
            // case timings (via callback) after they complete.  These GPE
            // routines are the last GPE routines added to the queue
            // during the RTL tick.
            G_fw_timing.rtl_start_gpe[1] = G_fw_timing.rtl_start;
            rc2 = gpe_request_schedule(G_fw_timing.gpe1_timing_request);

        }
        else
        {
            INCREMENT_ERR_HISTORY(ERRH_GPE1_NOT_IDLE);

            if(L_consec_trace_count[1] < MAX_CONSEC_TRACE)
            {
                xsr_sprg0.fields.xsr = in32(GPE_GPE1XIXSR);
                xsr_sprg0.fields.sprg0 = in32(GPE_GPE1XISPRG0);
                ir_edr.fields.edr = in32(GPE_GPE1XIEDR);
                ir_edr.fields.ir = in32(GPE_GPE1XIIR);
                iar_xsr.fields.iar = in32(GPE_GPE1XIIAR);
                TRAC_ERR("GPE1 programs did not complete within one tick. "
                         "XSR[0x%08x]  IAR[0x%08x] IR[0x%08x] EDR[0x%08x] SPRG0[0x%08X]",
                         xsr_sprg0.fields.xsr, iar_xsr.fields.iar,
                         ir_edr.fields.ir, ir_edr.fields.edr, xsr_sprg0.fields.sprg0);
                L_consec_trace_count[1]++;
            }
        }
    }
    if(rc || rc2)
    {
        /* @
         * @errortype
         * @moduleid    AMEC_UPDATE_FW_SENSORS
         * @reasoncode  SSX_GENERIC_FAILURE
         * @userdata1   return code - gpe0
         * @userdata2   return code - gpe1
         * @userdata4   OCC_NO_EXTENDED_RC
         * @devdesc     Failure to schedule PORE-GPE poreFlex object for FW timing
         *              analysis.
         */
        l_err = createErrl(
            AMEC_UPDATE_FW_SENSORS,             //modId
            SSX_GENERIC_FAILURE,                //reasoncode
            OCC_NO_EXTENDED_RC,                 //Extended reason code
            ERRL_SEV_INFORMATIONAL,             //Severity
            NULL,                               //Trace Buf
            DEFAULT_TRACE_SIZE,                 //Trace Size
            rc,                                 //userdata1
            rc2);                               //userdata2

        // commit error log
        commitErrl( &l_err );
    }

    // Process GPEs timings and determine whether to disable/enable 24x7
    if(l_gpe0_idle && l_gpe1_idle)
    {
        // Reset how many consecutive ticks we were busy for.
        L_busyTicks = 0;

        // If we were idle for at least 16 consecutive ticks, enable 24x7
        if( L_idleTicks >= 15 )
        {
            G_24x7_disabled = FALSE;
        }
        else
        {
            L_idleTicks++;
        }
    }
    else
    {
        // Reset how many consecutive ticks we were idle for
        L_idleTicks = 0;

        // If we were busy for at least 2 consecutive ticks, disable 24x7
        if( L_busyTicks >= 1 )
        {
            G_24x7_disabled = TRUE;
            INCREMENT_ERR_HISTORY(ERRH_24X7_DISABLED);
        }
        else
        {
            L_busyTicks++;
        }
    }

    L_first_call = FALSE;
}


// Function Specification
//
// Name: amec_update_fw_sensors
//
// Description: Updates sensors related to the OCC FW Timings
//
// Thread: RealTime Loop
//
// End Function Specification
#define MAX_CONSEC_TRACE 4
void amec_update_fw_sensors(void)
{
    // ------------------------------------------------------
    // Update OCC Firmware Sensors from last tick
    // ------------------------------------------------------
    int l_last_state = G_fw_timing.amess_state;
    // RTLtickdur    = duration of last tick's RTL ISR (max = 250us)
    sensor_update( AMECSENSOR_PTR(RTLtickdur), G_fw_timing.rtl_dur);
    // AMEintdur     = duration of last tick's AMEC portion of RTL ISR
    sensor_update( AMECSENSOR_PTR(AMEintdur), G_fw_timing.ameint_dur);
    // AMESSdurX     = duration of last tick's AMEC state
    if(l_last_state >= NUM_AMEC_SMH_STATES)
    {
        // Sanity check.  Trace this out, even though it should never happen.
        TRAC_INFO("AMEC State Invalid, Sensor Not Updated");
    }
    else
    {
        // AMESSdurX = duration of last tick's AMEC state
        sensor_update( AMECSENSOR_ARRAY_PTR(AMESSdur0, l_last_state),  G_fw_timing.amess_dur);
    }
}

/*----------------------------------------------------------------------------*/
/* End                                                                        */
/*----------------------------------------------------------------------------*/
OpenPOWER on IntegriCloud