summaryrefslogtreecommitdiffstats
path: root/src/occ_405/proc/proc_data_control.c
blob: 0733e6658435bc5da9017499fc04620d1c0cd8c9 (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
/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/occ_405/proc/proc_data_control.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                                                     */

#include "proc_data.h"
#include "proc_data_control.h"
#include "occhw_async.h"
#include "threadSch.h"
#include "pmc_register_addresses.h"
#include "proc_data_service_codes.h"
#include "occ_service_codes.h"
#include "errl.h"
#include "trac.h"
#include "rtls.h"
#include "apss.h"
#include "state.h"
#include "occ_sys_config.h"
#include "p9_pstates_common.h"
#include "pgpe_interface.h"
#include "rtls_service_codes.h"
#include "proc_pstate.h"

// The the GPE parameter fields for PGPE IPC calls.
extern GPE_BUFFER(ipcmsg_clip_update_t*  G_clip_update_parms_ptr);
extern GPE_BUFFER(ipcmsg_set_pmcr_t*     G_pmcr_set_parms_ptr);

extern GpeRequest G_clip_update_req;
extern GpeRequest G_pmcr_set_req;

extern bool G_state_transition_occuring;     // A state transition is currently going on?

// a global flag used by task_core_data_control() to indicate
// that the OCC is ready to transition to observation state
// (after initiatibg a clip update IPC task if needed)
bool G_active_to_observation_ready = false;

// create gpe request for GPE job. The initialization will be done one time
// during gpe request create.
GpeRequest G_core_data_control_req;

// Global double buffering for core data control
GPE_BUFFER(PstatesClips G_quads_data_control[2]) = {{{{0}}}};

// Pointer to the core data control that will be written to by the OCC FW.
GPE_BUFFER(PstatesClips* G_core_data_control_occwrite_ptr) = { &G_quads_data_control[0] };

// Pointer to the core data control that will be used by GPE engine.
GPE_BUFFER(PstatesClips* G_core_data_control_gpewrite_ptr) = { &G_quads_data_control[1] };


// Function Specification
//
// Name: task_core_data_control
//
// Description: Control quad actuation for all configured cores on every tick.
//
// End Function Specification
void task_core_data_control( task_t * i_task )
{
    errlHndl_t      err            = NULL;   //Error handler
    PstatesClips*   l_temp         = NULL;
    static bool     L_trace_logged = false;  // trace logging to avoid unnecessarily repeatig logs
    Pstate          l_pstate;

    // Once a state transition process starts, task data control
    // stops updating the PMCR/CLIPS updates, this way, the state
    // transition protocol can set the clips without colliding
    // with the task_core_data_control IPC tasks.
    if(G_state_transition_occuring)
    {
        if(L_trace_logged == false)
        {
            TRAC_INFO("task_core_data_control: Pstate Control stopped because a state transition started.");
            L_trace_logged = true;
        }

        // Only Transitioning to Observation state necessitates clip update
        // (if the last clip update was higher than legacy turbo).
        if ((G_occ_master_state == OCC_STATE_OBSERVATION) &&
            !G_active_to_observation_ready)
        {
            // confirm that the last clip update IPC successfully completed on PGPE (with no errors)
            if( async_request_is_idle(&G_clip_update_req.request) &&  //clip_update/set_clip_ranges completed
                (G_clip_update_parms_ptr->msg_cb.rc == PGPE_RC_SUCCESS) ) // with no errors
            {
                uint8_t quad = 0;
                Pstate pclip = 0xff;    // Initialize pclip to 0xff (lowest possible frequency)

                // Only if last clip update sent to PGPE is larger than legacy turbo,
                // send new clips with legacy turbo values, otherwise, no action needed.
                for (quad = 0; quad < MAX_QUADS; quad++)
                {
                    if(G_clip_update_parms_ptr->ps_val_clip_max[quad] < pclip)
                    {
                        // minimum pclip value corresponds to pstate of maximum frequency
                        pclip = G_clip_update_parms_ptr->ps_val_clip_max[quad];
                    }
                }
                l_pstate = proc_freq2pstate(G_sysConfigData.sys_mode_freq.table[OCC_MODE_TURBO]);
                // pclip of highest quad frequency corresponds to a frequency higher than legacy turbo
                if(pclip < l_pstate)
                {
                    pgpe_set_clip_ranges(l_pstate);
                }

                //Whether clips have been lowered from frequencies higher than legacy turbo
                //frequency, or already lower than turbo frequency, OCC is now ready to
                //transition to Observation state.
                G_active_to_observation_ready = true;
            }
        }
    }
    else
    {
        L_trace_logged = false;

        // perform Pstate/clip control if previous IPC call completed successfully
        // if not idle, ignore cycle
        // if an error was returned, log an error, and request reset
        if(G_sysConfigData.system_type.kvm) // OPAL system
        {
            // confirm that the clip update IPC from last cycle
            // has successfully completed on PGPE (with no errors)
            if( async_request_is_idle(&G_clip_update_req.request) &&  //clip_update/set_clip_ranges completed
                (G_clip_update_parms_ptr->msg_cb.rc == PGPE_RC_SUCCESS) ) // with no errors
            {
                //The previous OPAL PGPE request succeeded:

                //1) swap gpewrite ptr with the occwrite ptr (double buffering).
                l_temp = G_core_data_control_occwrite_ptr;
                G_core_data_control_occwrite_ptr = G_core_data_control_gpewrite_ptr;
                G_core_data_control_gpewrite_ptr = l_temp;

                //2) Set clip values from gpewrite's quad clips data-structure
                G_clip_update_parms_ptr = &G_core_data_control_gpewrite_ptr->clips;

                //call PGPE IPC function to update the clips
                pgpe_clip_update();
            }
            else if(G_clip_update_parms_ptr->msg_cb.rc != PGPE_RC_SUCCESS)
            {
                // an earlier clip update IPC call has not completed, trace and log an error
                TRAC_ERR("task_core_data_control: clip update IPC task returned an error, %d",
                         G_clip_update_parms_ptr->msg_cb.rc);

                /*
                 * @errortype
                 * @moduleid    RTLS_TASK_CORE_DATA_CONTROL_MOD
                 * @reasoncode  PGPE_FAILURE
                 * @userdata1   rc
                 * @userdata2   clip update task idle?
                 * @userdata4   ERC_PGPE_CLIP_UNSUCCESSFULL
                 * @devdesc     pgpe clip update returned an error
                 */
                err = createErrl(
                    RTLS_TASK_CORE_DATA_CONTROL_MOD,                  //ModId
                    PGPE_FAILURE,                                     //Reasoncode
                    ERC_PGPE_CLIP_UNSUCCESSFULL,                      //Extended reason code
                    ERRL_SEV_PREDICTIVE,                              //Severity
                    NULL,                                             //Trace Buf
                    DEFAULT_TRACE_SIZE,                               //Trace Size
                    G_clip_update_parms_ptr->msg_cb.rc,                    //Userdata1
                    async_request_is_idle(&G_clip_update_req.request) //Userdata2
                    );
            }
        }
        else
        {
            // NON OPAL System, OCC owns PMCR:
            if( async_request_is_idle(&G_pmcr_set_req.request) &&     // PMCR IPC from last TICK completed
                (G_pmcr_set_parms_ptr->msg_cb.rc == PGPE_RC_SUCCESS) )     // with no errors
            {
                //The previous Non-OPAL PGPE request succeeded:

                //1) swap gpewrite ptr with the occwrite ptr (double buffering).
                l_temp = G_core_data_control_occwrite_ptr;
                G_core_data_control_occwrite_ptr = G_core_data_control_gpewrite_ptr;
                G_core_data_control_gpewrite_ptr = l_temp;

                //2) Set Pstate values from gpewrite's quad pstates data-structure
                G_pmcr_set_parms_ptr = &G_core_data_control_gpewrite_ptr->pstates;

                //call PGPE IPC function to update Pstates
                pgpe_pmcr_set();
            }
            else if(G_pmcr_set_parms_ptr->msg_cb.rc != PGPE_RC_SUCCESS)
            {
                // an earlier clip update IPC call has not completed, trace and log an error
                TRAC_ERR("task_core_data_control: pstate update IPC task returned an error, %d",
                         G_pmcr_set_parms_ptr->msg_cb.rc);

                /*
                 * @errortype
                 * @moduleid    RTLS_TASK_CORE_DATA_CONTROL_MOD
                 * @reasoncode  PGPE_FAILURE
                 * @userdata1   rc
                 * @userdata2   pmcr set task idle?
                 * @userdata4   ERC_PGPE_PMCR_UNSUCCESSFULL
                 * @devdesc     pgpe PMCR set returned an error
                 */
                err = createErrl(
                    RTLS_TASK_CORE_DATA_CONTROL_MOD,               //ModId
                    PGPE_FAILURE,                                  //Reasoncode
                    ERC_PGPE_PMCR_UNSUCCESSFULL,                   //Extended reason code
                    ERRL_SEV_PREDICTIVE,                           //Severity
                    NULL,                                          //Trace Buf
                    DEFAULT_TRACE_SIZE,                            //Trace Size
                    G_pmcr_set_parms_ptr->msg_cb.rc,               //Userdata1
                    async_request_is_idle(&G_pmcr_set_req.request) //Userdata2
                    );
            }
        }

        if(err)
        {
            // commit error log
            REQUEST_RESET(err);
        }
    }

    return;
}
OpenPOWER on IntegriCloud