Beispiel #1
0
// Function Specification
//
// Name:  proc_trace_pstate_table_quick
//
// Description:  Debug Function to Print portion of Pstate Table
//               Eventually, this should trace key elements of Pstate
//               table to Trace Buffer.
//
// End Function Specification
void proc_trace_pstate_table_quick(void)
{
    GlobalPstateTable * l_gpst_ptr = NULL;

    l_gpst_ptr = gpsm_gpst();
    // Check the pointer since it may not have been installed on chips with 0 configured cores
    if(l_gpst_ptr == &G_global_pstate_table)
    {
        TRAC_IMP("GPST Installed:  Pstate[0]: %d kHz, Step: %d kHz, Entries: %d, Pvsafe[%d], Psafe[%d]",
                l_gpst_ptr->pstate0_frequency_khz,
                l_gpst_ptr->frequency_step_khz,
                (int8_t) l_gpst_ptr->entries,
                (int8_t) l_gpst_ptr->pvsafe,
                (int8_t) l_gpst_ptr->psafe
                );

        TRAC_IMP("Pmin[%d]: %d kHz, Pmax[%d]: %d kHz",
                (int8_t) l_gpst_ptr->pmin,
                (l_gpst_ptr->pstate0_frequency_khz + ((int8_t) l_gpst_ptr->pmin) * l_gpst_ptr->frequency_step_khz),
                ((int8_t) l_gpst_ptr->pmin + l_gpst_ptr->entries - 1),
                (l_gpst_ptr->pstate0_frequency_khz + ((int8_t) l_gpst_ptr->pmin + l_gpst_ptr->entries - 1) * l_gpst_ptr->frequency_step_khz)
                );
    }
    else
    {
        //This likely means that the processor has no configured cores (may not be an error scenario)
        TRAC_IMP("GPST not installed.  hw pointer= 0x%08x, present cores= 0x%08x", (uint32_t)l_gpst_ptr, G_present_cores);
    }
}
Beispiel #2
0
// Function Specification
//
// Name: SMGR_mode_transition_to_nominal
//
// Description:
//
// End Function Specification
errlHndl_t SMGR_mode_transition_to_nominal()
{
    errlHndl_t              l_errlHndl = NULL;

    TRAC_IMP("SMGR: Mode to Nominal Transition Started");

    // Set Freq Mode for AMEC to use
    l_errlHndl = amec_set_freq_range(OCC_MODE_NOMINAL);

    CURRENT_MODE() = OCC_MODE_NOMINAL;
    TRAC_IMP("SMGR: Mode to Nominal Transition Completed");

    return l_errlHndl;
}
Beispiel #3
0
// Function Specification
//
// Name: SMGR_mode_transition_to_powersave
//
// Description:
//
// End Function Specification
errlHndl_t SMGR_mode_transition_to_powersave()
{
    errlHndl_t              l_errlHndl = NULL;

    TRAC_IMP("SMGR: Mode to PowerSave Transition Started");

    // Set Freq Mode for AMEC to use
    l_errlHndl = amec_set_freq_range(OCC_MODE_PWRSAVE);

    CURRENT_MODE() = OCC_MODE_PWRSAVE;
    TRAC_IMP("SMGR: Mode to PowerSave Transition Completed");

    return l_errlHndl;
}
Beispiel #4
0
// Function Specification
//
// Name: SMGR_mode_transition_to_dynpowersave_fp
//
// Description:
//
// End Function Specification
errlHndl_t SMGR_mode_transition_to_dynpowersave_fp()
{
    errlHndl_t              l_errlHndl = NULL;

    TRAC_IMP("SMGR: Mode to Dynamic PowerSave-Favor Performance Transition Started");

    // Set Freq Mode for AMEC to use
    l_errlHndl = amec_set_freq_range(OCC_MODE_DYN_POWER_SAVE_FP);

    CURRENT_MODE() = OCC_MODE_DYN_POWER_SAVE_FP;
    TRAC_IMP("SMGR: Mode to Dynamic PowerSave-Favor Performance Transition Completed");

    return l_errlHndl;
}
Beispiel #5
0
// Function Specification
//
// Name: SMGR_mode_transition_to_ffo
//
// Description:
//
// End Function Specification
errlHndl_t SMGR_mode_transition_to_ffo()
{
    errlHndl_t              l_errlHndl = NULL;

    TRAC_IMP("SMGR: Mode to FFO Transition Started");

    // Set Freq Mode for AMEC to use
    l_errlHndl = amec_set_freq_range(OCC_MODE_FFO);

    CURRENT_MODE() = OCC_MODE_FFO;
    TRAC_IMP("SMGR: Mode to FFO Transition Completed");

    return l_errlHndl;
}
Beispiel #6
0
// Update I2C log information for specified engine
// i_op values:
//      LOC_ACQUIRE = OCC should take ownership of lock
//      LOC_RELEASE = OCC should release ownership of lock and notify host
void update_i2c_lock(const lockOperation_e i_op, const uint8_t i_engine)
{
    ocb_occflg_t occ_flags = {0};

#ifdef DEBUG_LOCK_TESTING
    ocb_occflg_t flag;
    flag.value = in32(OCB_OCCFLG);
    if (LOCK_RELEASE == i_op)
    {
        LOCK_DBG("update_i2c_lock: I2C engine %d RELEASE - host=%d, occ=%d, dimmTick=%d",
                 i_engine, flag.fields.i2c_engine3_lock_host, flag.fields.i2c_engine3_lock_occ, DIMM_TICK);
    }
    else
    {
        LOCK_DBG("update_i2c_lock: I2C engine %d LOCK    - host=%d, occ=%d, dimmTick=%d",
                 i_engine, flag.fields.i2c_engine3_lock_host, flag.fields.i2c_engine3_lock_occ, DIMM_TICK);
    }
#endif

    if (PIB_I2C_ENGINE_E == i_engine)
    {
        occ_flags.fields.i2c_engine3_lock_occ = 1;
    }
    else if (PIB_I2C_ENGINE_D == i_engine)
    {
        occ_flags.fields.i2c_engine2_lock_occ = 1;
    }
    else if (PIB_I2C_ENGINE_C == i_engine)
    {
        occ_flags.fields.i2c_engine1_lock_occ = 1;
    }

    if (LOCK_RELEASE == i_op)
    {
        out32(OCB_OCCFLG_CLR, occ_flags.value);

        // OCC had the lock and host wants it, so send interrupt to host
        notify_host(INTR_REASON_I2C_OWNERSHIP_CHANGE);

        TRAC_IMP("update_i2c_lock: OCC has released lock for I2C engine %d", i_engine);
    }
    else // LOCK_ACQUIRE
    {
        out32(OCB_OCCFLG_OR, occ_flags.value);

        TRAC_IMP("update_i2c_lock: OCC has acquired lock for I2C engine %d", i_engine);
    }

} // end update_i2c_lock()
Beispiel #7
0
//*************************************************************************
// Entry point function
//*************************************************************************
errlHndl_t traceTest(void * i_arg)
{
    errlHndl_t l_err = NULL;
    UINT l_rc = 0;

    do
    {
        // function unit test
        l_rc = traceFuncTest();
        if(l_rc)
        {
            printf("traceTest Applet: Function test failed\n");
            break;
        }

        // Macro test: test basic trace macros with/without parameters

        // int: supported
        TRAC_INFO(para_int_0);
        TRAC_INFO(para_int_1, 1);
        TRAC_INFO(para_int_5, 1, 2, 3, 4, 5);
        TRAC_INFO(para_int_6, 1, 2, 3, 4, 5, 6);

        // hex: supported
        TRAC_ERR(para_hex_0);
        TRAC_ERR(para_hex_1, 0xA);
        TRAC_ERR(para_hex_5, 0xA, 0xB, 0xC, 0xD, 0xE);
        TRAC_ERR(para_hex_6, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF);

        // char: not supported
        TRAC_IMP(para_int_0);
        TRAC_IMP(para_chr_1, "1");
        TRAC_IMP(para_chr_5, "1", "2", "3", "4", "5");
        TRAC_IMP(para_chr_6, "1", "2", "3", "4", "5", "6");

#ifdef TEST_SEMAPHORE
        // semaphore test
        l_rc = traceSemTest();
        if(l_rc)
        {
            printf("traceTest Applet: Semaphore test failed\n");
            break;
        }
#endif
    }while(0);

    printf("traceTest Applet: test finished\n");
    return l_err;
}
Beispiel #8
0
// Function Specification
//
// Name: reset_wof_clear_inhibit
//
// Description: This function clears the inhibit bits that are
// set as part of the WOF function
//
// End Function Specification
void reset_wof_clear_inhibit()
{
    uint64_t l_data64 = 0;
    uint32_t l_rc = 0;

    // Do not inhibit core wakeup anymore
    l_data64 = 0x0000000000000000ull;
    l_rc = _putscom(PDEMR, l_data64, SCOM_TIMEOUT);
    if (l_rc != 0)
    {
        TRAC_ERR("reset_wof_clear_inhibit: Error writing to PDEMR register! addr[0x%08X] rc[0x%08X]",
                 PDEMR,
                 l_rc);
    }
    else
    {
        TRAC_IMP("reset_wof_clear_inhibit: PDEMR register has been successfully cleared");
    }
}
Beispiel #9
0
int traceFuncTest()
{
    UINT l_rc = 0;
    UINT l_max_trace_entries = TRACE_BUFFER_SIZE / MIN_TRACE_ENTRY_SIZE;
    UINT l_entry_count = 0;
    UINT l_buffer_size = 0;
    tracDesc_t l_head = NULL;

    do
    {
        // Test target - trac_write_XXX(), TRAC_get_buffer() and TRAC_get_td()
        // This testcase would create l_max_trace_entries +1 trace entries
        // to fill trace buffer, times_wrap should be larger than zero
        do{
            l_entry_count++;
            TRAC_INFO("traceTest applet INFO record: count %d", (int)l_entry_count);
            TRAC_ERR("traceTest applet ERR record: count %d", (int)l_entry_count);
            TRAC_IMP("traceTest applet IMP record: count %d", (int)l_entry_count);
        }while(l_max_trace_entries >= l_entry_count);

        // Check times_wrap in TRAC_INFO.
        // Because structures are all the same, skip TRAC_ERR and TRAC_IMP
        l_rc = TRAC_get_buffer(TRAC_get_td("INF"), G_trac_buffer);
        l_head = (tracDesc_t)&G_trac_buffer;
        if((l_rc != 0 ) || (l_head->times_wrap == 0))
        {
            printf("Fail: times_wrap error in trace buffer: %d, %d\n", l_rc, l_head->times_wrap);
            break;
        }

        // Test target - TRAC_get_buffer() and TRAC_get_td()
        // case: invalid parameters
        l_rc = TRAC_get_buffer(TRAC_get_td("INF"), NULL);
        l_head = (tracDesc_t)&G_trac_buffer;
        if(l_rc == 0)
        {
            printf("TRAC_get_buffer(), reason code: %d\n", l_rc);
            printf("Fail: test TRAC_get_buffer() invalid 1th parameter\n");
            break;
        }

        l_rc = TRAC_get_buffer(NULL, G_trac_buffer);
        l_head = (tracDesc_t)&G_trac_buffer;
        if(l_rc == 0)
        {
            printf("TRAC_get_buffer(), reason code: %d\n", l_rc);
            printf("Fail: test TRAC_get_buffer() invalid 2nd parameter\n");
            break;
        }

        // Test target - TRAC_get_buffer_partial() and TRAC_get_td()
        // case: invalid parameters
        l_buffer_size = TRACE_BUFFER_SIZE;
        l_rc = TRAC_get_buffer_partial(NULL, G_trac_buffer, &l_buffer_size);
        if((l_rc != TRAC_INVALID_PARM) && (l_buffer_size !=0))
        {
            printf("TRAC_get_buffer_partial(), reason code: %d\n", l_rc);
            printf("Fail: test TRAC_get_buffer_partial() invalid 1st parameter\n");
            break;
        }

        l_rc = TRAC_get_buffer_partial(TRAC_get_td("UNKNOWN"), NULL, &l_buffer_size);
        if((l_rc != TRAC_INVALID_PARM) && (l_buffer_size !=0))
        {
            printf("TRAC_get_buffer_partial(), reason code: %d\n", l_rc);
            printf("Fail: test TRAC_get_buffer_partial() invalid 1st parameter\n");
            break;
        }

        l_rc = TRAC_get_buffer_partial(TRAC_get_td("INF"), NULL, &l_buffer_size);
        if((l_rc != TRAC_INVALID_PARM) && (l_buffer_size !=0))
        {
            printf("TRAC_get_buffer_partial(), reason code: %d\n", l_rc);
            printf("Fail: test TRAC_get_buffer_partial() invalid 2nd parameter\n");
            break;
        }

        l_rc = TRAC_get_buffer_partial(TRAC_get_td("ERR"), G_trac_buffer, NULL);
        if(l_rc != TRAC_INVALID_PARM)
        {
            printf("TRAC_get_buffer_partial(), reason code: %d\n", l_rc);
            printf("Fail: test TRAC_get_buffer_partial() invalid 3rd parameter\n");
            break;
        }

        // Test target - TRAC_get_buffer_partial()
        // case: input buffer less then the size of trace buffer header
        l_buffer_size = sizeof(trace_buf_head_t) - 1;
        l_rc = TRAC_get_buffer_partial(TRAC_get_td("IMP"), G_trac_buffer, &l_buffer_size);
        if(l_rc != TRAC_DATA_SIZE_LESS_THAN_HEADER_SIZE)
        {
            printf("TRAC_get_buffer_partial(), reason code: %d\n", l_rc);
            printf("Fail: test TRAC_get_buffer_partial() with illegal small input buffer\n");
            break;
        }

        // Test target - TRAC_get_buffer_partial()
        // case: input buffer is small then then trace buffer
        l_buffer_size = sizeof(trace_buf_head_t) + (TRACE_BUFFER_SIZE/4);
        l_rc = TRAC_get_buffer_partial(TRAC_get_td("INF"), G_trac_buffer, &l_buffer_size);
        if(l_rc)
        {
            printf("TRAC_get_buffer_partial(), reason code: %d\n", l_rc);
            printf("Fail: test TRAC_get_buffer_partial() with small input buffer\n");
            break;
        }

        // Test target - TRAC_get_buffer_partial()
        // case: input buffer is larger then trace buffer
        l_buffer_size = sizeof(G_trac_buffer);
        l_rc = TRAC_get_buffer_partial(TRAC_get_td("INF"), G_trac_buffer, &l_buffer_size);
        if(l_rc || (l_buffer_size != TRACE_BUFFER_SIZE))
        {
            printf("TRAC_get_buffer_partial(), reason code: %d size %d/%d\n", l_rc, l_buffer_size, TRACE_BUFFER_SIZE);
            printf("Fail: test TRAC_get_buffer_partial() with too large input buffer\n");
            break;
        }

        // Test target - TRAC_reset_buf() and TRAC_get_buffer_partial()
        // case: clear trace buffer and check with buffer larger than trace buffer
        TRAC_reset_buf();
        l_buffer_size = sizeof(G_trac_buffer);
        l_rc = TRAC_get_buffer_partial(TRAC_get_td("ERR"), G_trac_buffer, &l_buffer_size);
        if(l_rc)
        {
            printf("TRAC_get_buffer_partial(), reason code: %d\n", l_rc);
            printf("Fail: test TRAC_reset_buf()/TRAC_get_buffer_partial() with empty trace\n");
            break;
        }

        // Test target - TRAC_reset_buf() and TRAC_get_buffer_partial()
        // case: clear trace buffer and check it with buffer smaller than trace buffer
        TRAC_reset_buf();
        l_buffer_size = TRACE_BUFFER_SIZE/2;
        l_rc = TRAC_get_buffer_partial(TRAC_get_td("ERR"), G_trac_buffer, &l_buffer_size);
        if(l_rc)
        {
            printf("TRAC_get_buffer_partial(), reason code: %d\n", l_rc);
            printf("Fail: test TRAC_reset_buf()/TRAC_get_buffer_partial() with empty trace\n");
            break;
        }

        // Test target - TRAC_get_buffer_partial()
        // case: create some traces and test with large input buffer
        l_entry_count = 0;
        do{
            l_entry_count++;
            TRAC_INFO("traceTest applet INFO record: count %d", (int)l_entry_count);
            TRAC_ERR("traceTest applet ERR record: count %d", (int)l_entry_count);
            TRAC_IMP("traceTest applet IMP record: count %d", (int)l_entry_count);
        }while((l_max_trace_entries/4) >= l_entry_count);
        l_buffer_size = TRACE_BUFFER_SIZE;
        l_rc = TRAC_get_buffer_partial(TRAC_get_td("IMP"), G_trac_buffer, &l_buffer_size);
        l_head = (tracDesc_t)&G_trac_buffer;
        if(l_rc || (l_head->times_wrap != 0))
        {
            printf("TRAC_get_buffer_partial(), reason code: %d\n", l_rc);
            printf("Fail: test TRAC_get_buffer_partial() with large input buffer\n");
            break;
        }

        // Test target - TRAC_get_buffer_partial()
        // case: create some traces and test with small input buffer
        l_buffer_size = sizeof(trace_buf_head_t) + (TRACE_BUFFER_SIZE/4);
        l_rc = TRAC_get_buffer_partial(TRAC_get_td("INF"), G_trac_buffer, &l_buffer_size);
        if(l_rc)
        {
            printf("TRAC_get_buffer_partial(), reason code: %d\n", l_rc);
            printf("Fail: test TRAC_get_buffer_partial() with small input buffer\n");
            break;
        }

    }while(0);

    return l_rc;
}
Beispiel #10
0
// Function Specification
//
// Name: task_check_for_checkstop
//
// Description: Check for checkstop
//
// End Function Specification
void task_check_for_checkstop(task_t *i_self)
{
    pore_status_t l_gpe0_status;
    ocb_oisr0_t l_oisr0_status;
    static bool L_checkstop_traced = FALSE;
    uint8_t l_reason_code = 0;

    do
    {
        // This check is disabled once a checkstop or frozen GPE is detected
        if(L_checkstop_traced)
        {
            break;
        }

        // Looked for a frozen GPE, a sign that the chip has stopped working or
        // check-stopped.  This check also looks for an interrupt status flag that
        // indicates if the system has check-stopped.
        l_gpe0_status.value = in64(PORE_GPE0_STATUS);
        l_oisr0_status.value = in32(OCB_OISR0);

        if (l_gpe0_status.fields.freeze_action
            ||
            l_oisr0_status.fields.check_stop)
        {
            errlHndl_t l_err = NULL;

            if (l_gpe0_status.fields.freeze_action)
            {
                TRAC_IMP("Frozen GPE0 detected by RTL");
                l_reason_code = OCC_GPE_HALTED;
            }

            if (l_oisr0_status.fields.check_stop)
            {
                TRAC_IMP("System checkstop detected by RTL");
                l_reason_code = OCC_SYSTEM_HALTED;
            }

            L_checkstop_traced = TRUE;

            /*
             * @errortype
             * @moduleid    MAIN_SYSTEM_HALTED_MID
             * @reasoncode  OCC_GPE_HALTED
             * @userdata1   High order word of PORE_GPE0_STATUS
             * @userdata2   OCB_OISR0
             * @devdesc     OCC detected frozen GPE0
             */
            /*
             * @errortype
             * @moduleid    MAIN_SYSTEM_HALTED_MID
             * @reasoncode  OCC_SYSTEM_HALTED
             * @userdata1   High order word of PORE_GPE0_STATUS
             * @userdata2   OCB_OISR0
             * @devdesc     OCC detected system checkstop
             */
             l_err = createErrl(MAIN_SYSTEM_HALTED_MID,
                                l_reason_code,
                                OCC_NO_EXTENDED_RC,
                                ERRL_SEV_INFORMATIONAL,
                                NULL,
                                DEFAULT_TRACE_SIZE,
                                l_gpe0_status.words.high_order,
                                l_oisr0_status.value);

             // The commit code will check for the frozen GPE0 and system
             // checkstop conditions and take appropriate actions.
             commitErrl(&l_err);
        }
    }
    while(0);
}
Beispiel #11
0
// Function Specification
//
// Name: dcom_error_check
//
// Description: keep track of failure counts
//
// End Function Specification
void dcom_error_check( const dcom_error_type_t i_error_type, const bool i_clear_error, const uint32_t i_orc, const uint32_t i_orc_ext)
{
    static uint16_t L_rx_slv_outbox_fail_count = 0;
    uint16_t        l_modId = 0;
    uint16_t        *l_count_ptr = NULL;

    if ( i_error_type == SLAVE_INBOX )
    {
        l_count_ptr = &G_dcomSlvInboxCounter.currentFailCount;
        l_modId = DCOM_MID_TASK_RX_SLV_INBOX;
    }
    // if the i_error_type == SLAVE_OUTBOX then set the outbox count
    else
    {
        l_count_ptr = &L_rx_slv_outbox_fail_count;
        l_modId = DCOM_MID_TASK_RX_SLV_OUTBOX;
    }

    if ( i_clear_error )
    {
        *l_count_ptr = 0;
    }
    else
    {
        (*l_count_ptr)++;

        if ( *l_count_ptr == DCOM_250us_GAP )
        {
            // Trace an imp trace log
            TRAC_IMP("l_count_ptr[%d], L_outbox[%d], L_inbox[%d]",
                *l_count_ptr,
                L_rx_slv_outbox_fail_count,
                G_dcomSlvInboxCounter.currentFailCount );
        }
        else if ( *l_count_ptr == DCOM_4MS_GAP )
        {
            // Create and commit error log
            // NOTE: SRC tags are NOT needed here, they are
            //       taken care of by the caller
            errlHndl_t  l_errl = createErrl(
                l_modId,                        //ModId
                i_orc,                          //Reasoncode
                i_orc_ext,                      //Extended reasoncode
                ERRL_SEV_UNRECOVERABLE,         //Severity
                NULL,                           //Trace Buf
                DEFAULT_TRACE_SIZE,             //Trace Size
                *l_count_ptr,                   //Userdata1
                0                               //Userdata2
                );

            // Commit log
            commitErrl( &l_errl );

            // Call request nominal macro to change state
            REQUEST_NOMINAL();
        }
        else if ( *l_count_ptr == DCOM_1S_GAP )
        {
            // Create and commit error log
            // NOTE: SRC tags are NOT needed here, they are
            //       taken care of by the caller
            errlHndl_t  l_errl = createErrl(
                l_modId,                        //ModId
                i_orc,                          //Reasoncode
                i_orc_ext,                      //Extended reasoncode
                ERRL_SEV_UNRECOVERABLE,         //Severity
                NULL,                           //Trace Buf
                DEFAULT_TRACE_SIZE,             //Trace Size
                *l_count_ptr,                   //Userdata1
                0                               //Userdata2
                );

            // Commit log
            // Call request reset macro
            REQUEST_RESET(l_errl);
        }
    }
}
Beispiel #12
0
// Function Specification
//
// Name: dcom_initialize_roles
//
// Description: Initialize roles so we know if we are master or slave
//
// End Function Specification
void dcom_initialize_roles(void)
{
    G_occ_role = OCC_SLAVE;

    // Locals
    pba_xcfg_t pbax_cfg_reg;

    // Used as a debug tool to correlate time between OCCs & System Time
    // getscom_ffdc(OCB_OTBR, &G_dcomTime.tod, NULL); // Commits errors internally

    G_dcomTime.tod = in64(OCB_OTBR) >> 4;
    G_dcomTime.base = ssx_timebase_get();
    pbax_cfg_reg.value = in64(PBA_XCFG);

    if(pbax_cfg_reg.fields.rcv_groupid < MAX_NUM_NODES &&
       pbax_cfg_reg.fields.rcv_chipid < MAX_NUM_OCC)
    {

        TRAC_IMP("Proc ChipId (%d)  NodeId (%d)",
                 pbax_cfg_reg.fields.rcv_chipid,
                 pbax_cfg_reg.fields.rcv_groupid);

        G_pbax_id.valid     = 1;
        G_pbax_id.node_id   = pbax_cfg_reg.fields.rcv_groupid;
        G_pbax_id.chip_id   = pbax_cfg_reg.fields.rcv_chipid;
        G_pbax_id.module_id = G_pbax_id.chip_id;
        // Always start as OCC Slave
        G_occ_role = OCC_SLAVE;
        rtl_set_run_mask(RTL_FLAG_NOTMSTR);


        // Set the initial presence mask, and count the number of occ's present
        G_sysConfigData.is_occ_present |= (0x01 << G_pbax_id.chip_id);
        G_occ_num_present = __builtin_popcount(G_sysConfigData.is_occ_present);

    }
    else // Invalid chip/node ID(s)
    {
        TRAC_ERR("Proc ChipId (%d) and/or NodeId (%d) too high: request reset",
                 pbax_cfg_reg.fields.rcv_chipid,
                 pbax_cfg_reg.fields.rcv_groupid);
        /* @
         * @errortype
         * @moduleid    DCOM_MID_INIT_ROLES
         * @reasoncode  INVALID_CONFIG_DATA
         * @userdata1   PBAXCFG (upper)
         * @userdata2   PBAXCFG (lower)
         * @userdata4   ERC_CHIP_IDS_INVALID
         * @devdesc     Failure determining OCC role
         */
        errlHndl_t  l_errl = createErrl(
            DCOM_MID_INIT_ROLES,            //ModId
            INVALID_CONFIG_DATA,            //Reasoncode
            ERC_CHIP_IDS_INVALID,           //Extended reasoncode
            ERRL_SEV_UNRECOVERABLE,         //Severity
            NULL,                           //Trace Buf
            DEFAULT_TRACE_SIZE,             //Trace Size
            pbax_cfg_reg.words.high_order,  //Userdata1
            pbax_cfg_reg.words.low_order    //Userdata2
            );

        // Callout firmware
        addCalloutToErrl(l_errl,
                         ERRL_CALLOUT_TYPE_COMPONENT_ID,
                         ERRL_COMPONENT_ID_FIRMWARE,
                         ERRL_CALLOUT_PRIORITY_HIGH);

        //Add processor callout
        addCalloutToErrl(l_errl,
                         ERRL_CALLOUT_TYPE_HUID,
                         G_sysConfigData.proc_huid,
                         ERRL_CALLOUT_PRIORITY_LOW);

        G_pbax_id.valid   = 0;  // Invalid Chip/Node ID
    }

// Initialize DCOM Thread Sem
    ssx_semaphore_create( &G_dcomThreadWakeupSem, // Semaphore
                          1,                      // Initial Count
                          0);                     // No Max Count

}
Beispiel #13
0
// Function Specification
//
// Name:  proc_gpsm_dcm_sync_enable_pstates_smh
//
// Description:  Step through all the states & synch needed to enable
//               Pstates on both master & slave on a DCM.  This also
//               works for a SCM, which will act as DCM master (as far
//               as this function is concerned.)
//
// End Function Specification
void proc_gpsm_dcm_sync_enable_pstates_smh(void)
{
    // Static Locals
    static GpsmEnablePstatesMasterInfo l_master_info;
    static Pstate l_voltage_pstate, l_freq_pstate;

    // Local Variables
    int l_rc = 0;
    errlHndl_t l_errlHndl = NULL;

    if(!gpsm_dcm_slave_p())
    {
        // ---------------------------------------
        // SCM or DCM Master
        // ---------------------------------------
        switch( G_proc_dcm_sync_state.sync_state_master )
        {
            case PROC_GPSM_SYNC_NO_PSTATE_TABLE:
                // Waiting for Pstate Table from TMGT
                break;

            case PROC_GPSM_SYNC_PSTATE_TABLE_INSTALLED:
                PROC_DBG("GPST DCM Master State %d\n",G_proc_dcm_sync_state.sync_state_master);
                // DCM SYNC (MasterWaitForSlave):  Wait for slave to install Pstate table
                if(gpsm_dcm_mode_p()){
                    if( G_proc_dcm_sync_state.sync_state_slave == PROC_GPSM_SYNC_PSTATE_TABLE_INSTALLED)
                    {
                        // Move to next state in state machine
                        G_proc_dcm_sync_state.sync_state_master = PROC_GPSM_SYNC_READY_TO_ENABLE_MASTER;
                    }
                }
                else
                {
                    // Move to next state in state machine
                    G_proc_dcm_sync_state.sync_state_master = PROC_GPSM_SYNC_READY_TO_ENABLE_MASTER;
                }
                break;

            case  PROC_GPSM_SYNC_READY_TO_ENABLE_MASTER:
                PROC_DBG("GPST DCM Master State %d\n",G_proc_dcm_sync_state.sync_state_master);

                // Pstate tables has been installed, so now Master can start to enable Pstates
                l_rc = gpsm_enable_pstates_master(&l_master_info, &l_voltage_pstate, &l_freq_pstate);
                if(l_rc)
                {
                    // Error
                    TRAC_ERR("MSTR: gpsm_enable_pstates_master failed with rc=0x%08x", l_rc);
                    G_proc_dcm_sync_state.sync_state_master =  PROC_GPSM_SYNC_PSTATE_ERROR;
                    break;
                }
                TRAC_IMP("MSTR: Initial Pstates: V: %d, F: %d\n",l_voltage_pstate, l_freq_pstate);

                // DCM SYNC (Master2Slave):  Send V & F Pstate to slave
                G_proc_dcm_sync_state.dcm_pair_id = G_pob_id.chip_id;
                G_proc_dcm_sync_state.pstate_v = l_voltage_pstate;
                G_proc_dcm_sync_state.pstate_f = l_freq_pstate;

                // Move to next state in state machine
                G_proc_dcm_sync_state.sync_state_master = PROC_GPSM_SYNC_PSTATE_MASTER_ENABLED;
                break;

            case  PROC_GPSM_SYNC_PSTATE_MASTER_ENABLED:
                PROC_DBG("GPST DCM Master State %d\n",G_proc_dcm_sync_state.sync_state_master);
                // DCM SYNC (MasterWaitForSlave):  Wait for slave to complete gpsm_enable_pstates_slave()
                if(gpsm_dcm_mode_p()){
                    if( G_proc_dcm_sync_state.sync_state_slave == PROC_GPSM_SYNC_PSTATE_SLAVE_ENABLED)
                    {
                        // Move to next state in state machine
                        G_proc_dcm_sync_state.sync_state_master = PROC_GPSM_SYNC_READY_TO_ENABLE_SLAVE;
                    }
                }
                else
                {
                    G_proc_dcm_sync_state.sync_state_master = PROC_GPSM_SYNC_READY_TO_ENABLE_SLAVE;
                }
                break;


            case PROC_GPSM_SYNC_READY_TO_ENABLE_SLAVE:
                PROC_DBG("GPST DCM Master State %d\n",G_proc_dcm_sync_state.sync_state_master);

                // Master does next step of enabling Pstates, now that slave has done it's enable
                l_rc = gpsm_enable_pstates_slave(&l_master_info, l_voltage_pstate, l_freq_pstate);
                if(l_rc)
                {
                    // Error
                    TRAC_ERR("MSTR: gpsm_enable_pstates_slave failed with rc=0x%08x", l_rc);
                    G_proc_dcm_sync_state.sync_state_master =  PROC_GPSM_SYNC_PSTATE_ERROR;
                    break;
                }
                TRAC_INFO("MSTR: Completed DCM Pstate Slave Init\n");
                G_proc_dcm_sync_state.sync_state_master = PROC_GPSM_SYNC_PSTATE_SLAVE_ENABLED;
                break;

            case PROC_GPSM_SYNC_PSTATE_SLAVE_ENABLED:
                PROC_DBG("GPST DCM Master State %d\n",G_proc_dcm_sync_state.sync_state_master);
                // Master puts this chip in Pstate HW mode
                l_rc = gpsm_hw_mode();
                if(l_rc)
                {
                    // Error
                    TRAC_ERR("MSTR: gpsm_hw_mode failed with rc=0x%08x", l_rc);
                    G_proc_dcm_sync_state.sync_state_master =  PROC_GPSM_SYNC_PSTATE_ERROR;
                    break;
                }
                // DCM SYNC (Master2Slave):  Tell Slave Master has entered HW mmode
                G_proc_dcm_sync_state.sync_state_master = PROC_GPSM_SYNC_PSTATE_HW_MODE;
                break;

            case PROC_GPSM_SYNC_PSTATE_HW_MODE:
                PROC_DBG("GPST DCM Master State %d\n",G_proc_dcm_sync_state.sync_state_master);
                // DCM SYNC (Master2Slave): Wait for Slave to Enter HW Mode
                if(gpsm_dcm_mode_p()){
                    if( G_proc_dcm_sync_state.sync_state_slave == PROC_GPSM_SYNC_PSTATE_HW_MODE)
                    {
                        TRAC_INFO("MSTR: Completed DCM Pstate Enable");
                        G_proc_dcm_sync_state.sync_state_master = PROC_GPSM_SYNC_PSTATE_HW_MODE_ENABLED;

                        //do additional setup if in kvm mode
                        proc_pstate_kvm_setup();
                    }
                }
                else
                {
                    G_proc_dcm_sync_state.sync_state_master = PROC_GPSM_SYNC_PSTATE_HW_MODE_ENABLED;
                    TRAC_INFO("MSTR: Completed SCM Pstate Enable");

                    //do additional setup if in kvm mode
                    proc_pstate_kvm_setup();
                }
                break;

            case PROC_GPSM_SYNC_PSTATE_HW_MODE_ENABLED:
                // Final State
                // Pstates Enabled on both modules in DCM
                break;

           case PROC_GPSM_SYNC_PSTATE_ERROR:
               // Do nothing, something will have to come and kick us out of this state
               break;

            default:
                G_proc_dcm_sync_state.sync_state_master = PROC_GPSM_SYNC_NO_PSTATE_TABLE;
                break;
        }
    }
    else if (gpsm_dcm_slave_p())
    {
        // ---------------------------------------
        // DCM Slave
        //  - Don't need to check if DCM, since we can't come in here unless DCM
        // ---------------------------------------

       switch( G_proc_dcm_sync_state.sync_state_slave)
       {
           case PROC_GPSM_SYNC_NO_PSTATE_TABLE:
               // Waiting for Pstate Table from TMGT
               break;

           case PROC_GPSM_SYNC_PSTATE_TABLE_INSTALLED:
               // Pstate table has been installed, but slave needs to wait
               // for master before it can do anything else.

               // DCM SYNC (SlaveWaitForMaster):  Send V & F Pstate to slave
               // Wait for Master to complete gpsm_enable_pstates_master()
               // before running gpsm_enable_pstates_slave()
               if( G_proc_dcm_sync_state.sync_state_master == PROC_GPSM_SYNC_PSTATE_MASTER_ENABLED)
               {
                   // Go to next state
                   G_proc_dcm_sync_state.sync_state_slave = PROC_GPSM_SYNC_PSTATE_MASTER_ENABLED;
               }
               break;


           case PROC_GPSM_SYNC_PSTATE_MASTER_ENABLED:
               PROC_DBG("GPST DCM Slave State %d\n",G_proc_dcm_sync_state.sync_state_slave);
               // Read the initial Pstates from the data DCM master sent
               l_voltage_pstate = G_proc_dcm_sync_state.pstate_v;
               l_freq_pstate = G_proc_dcm_sync_state.pstate_f;

               // NULL is passed to this function when run on dcm slave
               l_rc = gpsm_enable_pstates_slave(NULL, l_voltage_pstate, l_freq_pstate);
               if(l_rc)
               {
                   // Error
                   TRAC_ERR("SLV: gpsm_enable_pstates_slave failed with rc=0x%08x", l_rc);
                   G_proc_dcm_sync_state.sync_state_slave =  PROC_GPSM_SYNC_PSTATE_ERROR;
                   break;
               }
               TRAC_INFO("SLV: Completed DCM Pstate Slave Init\n");

               // DCM SYNC (Slave2Master):
               // Tell Master that slave has run gpsm_enable_pstates_slave()

               // Go to next state
               G_proc_dcm_sync_state.sync_state_slave = PROC_GPSM_SYNC_PSTATE_SLAVE_ENABLED;
               break;

           case PROC_GPSM_SYNC_PSTATE_SLAVE_ENABLED:
               // DCM SYNC (SlaveWaitForMaster):  Wait for Master to run gpsm_hw_mode
               if( G_proc_dcm_sync_state.sync_state_master == PROC_GPSM_SYNC_PSTATE_HW_MODE)
               {
                   // Enter Pstate HW mode
                   l_rc = gpsm_hw_mode();
                   if(l_rc)
                   {
                       // Error
                       TRAC_ERR("SLV: gpsm_hw_mode failed with rc=0x%08x", l_rc);
                       G_proc_dcm_sync_state.sync_state_slave =  PROC_GPSM_SYNC_PSTATE_ERROR;
                       break;
                   }

                   // DCM SYNC (Slave2Master): Tell master that DCM slave made it to HW mode

                   // Go to next state
                   G_proc_dcm_sync_state.sync_state_slave = PROC_GPSM_SYNC_PSTATE_HW_MODE;
               }
               break;

           case PROC_GPSM_SYNC_PSTATE_HW_MODE:
               // Slave & Master now both know each other has HW mode enabled
               if( G_proc_dcm_sync_state.sync_state_master == PROC_GPSM_SYNC_PSTATE_HW_MODE_ENABLED)
               {
                   G_proc_dcm_sync_state.sync_state_slave = PROC_GPSM_SYNC_PSTATE_HW_MODE_ENABLED;
                   TRAC_INFO("SLV: Completed DCM Pstate Enable");

                   //do additional setup if in kvm mode
                   proc_pstate_kvm_setup();
               }
               break;

           case PROC_GPSM_SYNC_PSTATE_HW_MODE_ENABLED:
               // Final State
               // Pstates Enabled on both modules in DCM
               break;

           case PROC_GPSM_SYNC_PSTATE_ERROR:
               // Do nothing, something will have to come and kick us out of this state
               break;

           default:
               G_proc_dcm_sync_state.sync_state_slave = PROC_GPSM_SYNC_NO_PSTATE_TABLE;
               break;

       }
    }

    // If we are in the process of running through the state machine,
    // we will do a sem_post to speed up the DCOM Thread and step us
    // through faster.
    if( PROC_GPSM_SYNC_NO_PSTATE_TABLE != proc_gpsm_dcm_sync_get_my_state()
        && !proc_is_hwpstate_enabled() )
    {
       ssx_semaphore_post(&G_dcomThreadWakeupSem);
    }

    // If we broke out of loops above because of an error, create an
    // error log and return it to caller.
    if(l_rc)
    {
        /* @
         * @errortype
         * @moduleid    PROC_ENABLE_PSTATES_SMH_MOD
         * @reasoncode  SSX_GENERIC_FAILURE
         * @userdata1   SRAM Address of the Pstate Table
         * @userdata2   Return Code of call that failed
         * @userdata4   OCC_NO_EXTENDED_RC
         * @devdesc     Failed to install Pstate Table
         */
        l_errlHndl = createErrl(
                PROC_ENABLE_PSTATES_SMH_MOD,        //modId
                SSX_GENERIC_FAILURE,                //reasoncode
                OCC_NO_EXTENDED_RC,                 //Extended reason code
                ERRL_SEV_PREDICTIVE,                //Severity
                NULL,    //TODO: create trace       //Trace Buf
                DEFAULT_TRACE_SIZE,                 //Trace Size
                (uint32_t) &G_global_pstate_table,  //userdata1
                l_rc);                              //userdata2
        addCalloutToErrl(l_errlHndl,
                         ERRL_CALLOUT_TYPE_COMPONENT_ID,
                         ERRL_COMPONENT_ID_FIRMWARE,
                         ERRL_CALLOUT_PRIORITY_HIGH);
        addCalloutToErrl(l_errlHndl,
                         ERRL_CALLOUT_TYPE_HUID,
                         G_sysConfigData.proc_huid,
                         ERRL_CALLOUT_PRIORITY_LOW);
        REQUEST_RESET(l_errlHndl);
    }

    return;
}
Beispiel #14
0
// Function Specification
//
// Name:  proc_pstate_kvm_setup
//
// Description: Get everything set up for KVM mode
//
// End Function Specification
void proc_pstate_kvm_setup()
{
    int                                 l_core;
    int                                 l_rc = 0;
    uint32_t                            l_configured_cores;
    pcbs_pcbspm_mode_reg_t              l_ppmr;
    pcbs_pmgp1_reg_t                    l_pmgp1;
    pcbs_power_management_bounds_reg_t  l_pmbr;
    errlHndl_t                          l_errlHndl;

    do
    {
        //only run this in KVM mode
        if(!G_sysConfigData.system_type.kvm)
        {
            break;
        }

        l_configured_cores = ~in32(PMC_CORE_DECONFIGURATION_REG);

        // Do per-core configuration
        for(l_core = 0; l_core < PGP_NCORES; l_core++, l_configured_cores <<= 1)
        {
            if(!(l_configured_cores & 0x80000000)) continue;

            //do read-modify-write to allow pmax clip to also clip voltage (not just frequency)
            l_rc = getscom_ffdc(CORE_CHIPLET_ADDRESS(PCBS_PCBSPM_MODE_REG, l_core),
                       &(l_ppmr.value), NULL); //commit errors internally
            if(l_rc)
            {
                TRAC_ERR("proc_pstate_kvm_setup: getscom(PCBS_PCBSPM_MODE_REG) failed. rc=%d, hw_core=%d",
                         l_rc, l_core);
                break;
            }
            l_ppmr.fields.enable_clipping_of_global_pstate_req = 1;
            l_rc = putscom_ffdc(CORE_CHIPLET_ADDRESS(PCBS_PCBSPM_MODE_REG, l_core),
                 l_ppmr.value, NULL); //commit errors internally
            if(l_rc)
            {
                TRAC_ERR("proc_pstate_kvm_setup: putscom(PCBS_PCBSPM_MODE_REG) failed. rc=%d, hw_core=%d",
                         l_rc, l_core);
                break;
            }

            //per Vaidy Srinivasan, clear bit 11 in the Power Management GP1 register
            l_pmgp1.value = 0;
            l_pmgp1.fields.pm_spr_override_en = 1;
            l_rc = putscom_ffdc(CORE_CHIPLET_ADDRESS(PCBS_PMGP1_REG_AND, l_core),
                           ~l_pmgp1.value, NULL); //commit errors internally
            if(l_rc)
            {
                TRAC_ERR("proc_pstate_kvm_setup: putscom(PCBS_PMGB1_REG_OR) failed. rc=0x%08x, hw_core=%d",
                         l_rc, l_core);
                break;
            }

            //set pmax/pmin clip initial settings
            l_pmbr.value = 0;
            l_pmbr.fields.pmin_clip = gpst_pmin(&G_global_pstate_table)+1; //Per David Du, we must use pmin+1 to avoid gpsa hang
            l_pmbr.fields.pmax_clip = gpst_pmax(&G_global_pstate_table);
            l_rc = putscom_ffdc(CORE_CHIPLET_ADDRESS(PCBS_POWER_MANAGEMENT_BOUNDS_REG, l_core),
                           l_pmbr.value, NULL); //commit errors internally
            if(l_rc)
            {
                TRAC_ERR("proc_pstate_kvm_setup: putscom(PCBS_POWER_MANAGEMENT_BOUNDS_REG) failed. rc=0x%08x, hw_core=%d",
                         l_rc, l_core);
                break;
            }

        }// end of per-core config

        if(l_rc)
        {
            break;
        }

        // Set the voltage clipping register to match the pmax/pmin clip values set above.
        pmc_rail_bounds_register_t prbr;
        prbr.value = in32(PMC_RAIL_BOUNDS_REGISTER);
        prbr.fields.pmin_rail = gpst_pmin(&G_global_pstate_table);
        prbr.fields.pmax_rail = gpst_pmax(&G_global_pstate_table);
        TRAC_IMP("pmin clip pstate = %d, pmax clip pstate = %d", prbr.fields.pmin_rail, prbr.fields.pmax_rail);
        out32(PMC_RAIL_BOUNDS_REGISTER, prbr.value);

        // Initialize the sapphire table in SRAM (sets valid bit)
        populate_pstate_to_sapphire_tbl();

        // copy sram image into mainstore HOMER
        populate_sapphire_tbl_to_mem();
        TRAC_IMP("proc_pstate_kvm_setup: RUNNING IN KVM MODE");
    }while(0);

    if(l_rc)
    {
        // Create Error Log and request reset
        /* @
         * @errortype
         * @moduleid    PROC_PSTATE_KVM_SETUP_MOD
         * @reasoncode  PROC_SCOM_ERROR
         * @userdata1   l_configured_cores
         * @userdata2   Return Code of call that failed
         * @userdata4   OCC_NO_EXTENDED_RC
         * @devdesc     OCC failed to scom a core register
         */
        l_errlHndl = createErrl(
                PROC_PSTATE_KVM_SETUP_MOD,          //modId
                PROC_SCOM_ERROR,                    //reasoncode
                OCC_NO_EXTENDED_RC,                 //Extended reason code
                ERRL_SEV_PREDICTIVE,                //Severity
                NULL,                               //Trace Buf
                DEFAULT_TRACE_SIZE,                 //Trace Size
                l_configured_cores,                 //userdata1
                l_rc                                //userdata2
                );

        addCalloutToErrl(l_errlHndl,
                ERRL_CALLOUT_TYPE_HUID,
                G_sysConfigData.proc_huid,
                ERRL_CALLOUT_PRIORITY_HIGH);
        addCalloutToErrl(l_errlHndl,
                ERRL_CALLOUT_TYPE_COMPONENT_ID,
                ERRL_COMPONENT_ID_FIRMWARE,
                ERRL_CALLOUT_PRIORITY_MED);

        REQUEST_RESET(l_errlHndl);
    }
}
Beispiel #15
0
//////////////////////////
// Function Specification
//
// Name: amec_gpu_pcap
//
// Description: Determine power cap for GPUs
//
// Thread: Real Time Loop
//
// End Function Specification
void amec_gpu_pcap(bool i_oversubscription, bool i_active_pcap_changed, int32_t i_avail_power)
{
    /*------------------------------------------------------------------------*/
    /*  Local Variables                                                       */
    /*------------------------------------------------------------------------*/
    uint8_t  i = 0;
    uint32_t l_gpu_cap_mw = 0;
    uint16_t l_system_gpu_total_pcap = 0;  // total GPU pcap required by system based on if currently in oversub or not
    static uint16_t L_total_gpu_pcap = 0;  // Current total GPU pcap in effect
    static uint16_t L_n_plus_1_mode_gpu_total_pcap = 0;  // Total GPU pcap required for N+1 (not in oversubscription)
    static uint16_t L_n_mode_gpu_total_pcap = 0;  // Total GPU pcap required for oversubscription
    static uint16_t L_active_psr_gpu_total_pcap = 0; // Total GPU pcap for the currently set pcap and PSR
    static uint16_t L_per_gpu_pcap = 0;  // Amount of L_total_gpu_pcap for each GPU
    static uint8_t L_psr = 100;   // PSR value used in L_active_psr_gpu_total_pcap calculation
    static bool L_first_run = TRUE;  // for calculations done only 1 time

    static uint32_t L_last_pcap_traced[MAX_NUM_GPU_PER_DOMAIN] = {0};

    /*------------------------------------------------------------------------*/
    /*  Code                                                                  */
    /*------------------------------------------------------------------------*/
    // If this is the first time running calculate the total GPU power cap for system power caps (N and N+1)
    if(L_first_run)
    {
       // calculate total GPU power cap for oversubscription
       if(g_amec->pcap.ovs_node_pcap > G_sysConfigData.total_non_gpu_max_pwr_watts)
       {
           // Take all non-GPU power away from the oversubscription power cap
           L_n_mode_gpu_total_pcap = g_amec->pcap.ovs_node_pcap - G_sysConfigData.total_non_gpu_max_pwr_watts;
           // Add back in the power that will be dropped by processor DVFS and memory throttling and give to GPUs
           L_n_mode_gpu_total_pcap += G_sysConfigData.total_proc_mem_pwr_drop_watts;
       }
       else
       {
           // This should not happen, the total non GPU power should never be higher than the N mode cap
           // Log error and set GPUs to minimum power cap
           L_n_mode_gpu_total_pcap = 0; // this will set minimum GPU power cap

           TRAC_ERR("amec_gpu_pcap: non GPU max power %dW is more than N mode pwr limit %dW",
                     G_sysConfigData.total_non_gpu_max_pwr_watts, g_amec->pcap.ovs_node_pcap);

           /* @
            * @errortype
            * @moduleid    AMEC_GPU_PCAP_MID
            * @reasoncode  GPU_FAILURE
            * @userdata1   N mode Power Cap watts
            * @userdata2   Total non-GPU power watts
            * @userdata4   ERC_GPU_N_MODE_PCAP_CALC_FAILURE
            * @devdesc     Total non-GPU power more than N mode power cap
            *
            */
           errlHndl_t l_err = createErrl(AMEC_GPU_PCAP_MID,
                                         GPU_FAILURE,
                                         ERC_GPU_N_MODE_PCAP_CALC_FAILURE,
                                         ERRL_SEV_PREDICTIVE,
                                         NULL,
                                         DEFAULT_TRACE_SIZE,
                                         g_amec->pcap.ovs_node_pcap,
                                         G_sysConfigData.total_non_gpu_max_pwr_watts);

           //Callout firmware
           addCalloutToErrl(l_err,
                            ERRL_CALLOUT_TYPE_COMPONENT_ID,
                            ERRL_COMPONENT_ID_FIRMWARE,
                            ERRL_CALLOUT_PRIORITY_HIGH);
           commitErrl(&l_err);
       }

       // calculate total GPU power cap for N+1 (not in oversubscription)
       if(G_sysConfigData.pcap.system_pcap > G_sysConfigData.total_non_gpu_max_pwr_watts)
       {
           // Take all non-GPU power away from the N+1 power cap
           L_n_plus_1_mode_gpu_total_pcap = G_sysConfigData.pcap.system_pcap - G_sysConfigData.total_non_gpu_max_pwr_watts;
           // Add back in the power that will be dropped by processor DVFS and memory throttling and give to GPUs
           L_n_plus_1_mode_gpu_total_pcap += G_sysConfigData.total_proc_mem_pwr_drop_watts;
       }
       else
       {
           // This should not happen, the total non GPU power should never be higher than the N+1 mode cap
           // Log error and set GPUs to minimum power cap
           L_n_plus_1_mode_gpu_total_pcap = 0; // this will set minimum GPU power cap

           TRAC_ERR("amec_gpu_pcap: non GPU max power %dW is more than N+1 mode pwr limit %dW",
                     G_sysConfigData.total_non_gpu_max_pwr_watts, G_sysConfigData.pcap.system_pcap);

           /* @
            * @errortype
            * @moduleid    AMEC_GPU_PCAP_MID
            * @reasoncode  GPU_FAILURE
            * @userdata1   N+1 mode Power Cap watts
            * @userdata2   Total non-GPU power watts
            * @userdata4   ERC_GPU_N_PLUS_1_MODE_PCAP_CALC_FAILURE
            * @devdesc     Total non-GPU power more than N+1 mode power cap
            *
            */
           errlHndl_t l_err = createErrl(AMEC_GPU_PCAP_MID,
                                         GPU_FAILURE,
                                         ERC_GPU_N_PLUS_1_MODE_PCAP_CALC_FAILURE,
                                         ERRL_SEV_PREDICTIVE,
                                         NULL,
                                         DEFAULT_TRACE_SIZE,
                                         G_sysConfigData.pcap.system_pcap,
                                         G_sysConfigData.total_non_gpu_max_pwr_watts);

           //Callout firmware
           addCalloutToErrl(l_err,
                            ERRL_CALLOUT_TYPE_COMPONENT_ID,
                            ERRL_COMPONENT_ID_FIRMWARE,
                            ERRL_CALLOUT_PRIORITY_HIGH);
           commitErrl(&l_err);
       }
    }  // if first run

    // Calculate the total GPU power cap for the current active limit and PSR
    // this only needs to be calculated if either the active limit or PSR changed
    if( (L_first_run) || (i_active_pcap_changed) || (L_psr != G_sysConfigData.psr) )
    {
       L_psr = G_sysConfigData.psr;
       if(g_amec->pcap.active_node_pcap > G_sysConfigData.total_non_gpu_max_pwr_watts)
       {
           // Take all non-GPU power away from the active power cap
           L_active_psr_gpu_total_pcap = g_amec->pcap.active_node_pcap - G_sysConfigData.total_non_gpu_max_pwr_watts;
           // Add back in the power that will be dropped by processor DVFS and memory throttling based on the PSR
           // to give to GPUs
           L_active_psr_gpu_total_pcap += ( (L_psr / 100) * G_sysConfigData.total_proc_mem_pwr_drop_watts );
       }
       else
       {
           // Set GPUs to minimum power cap
           L_active_psr_gpu_total_pcap = 0;
           TRAC_IMP("amec_gpu_pcap: non GPU max power %dW is more than active pwr limit %dW",
                     G_sysConfigData.total_non_gpu_max_pwr_watts, g_amec->pcap.active_node_pcap);
       }

       // Total GPU power cap is the lower of system (N+1 or oversubscription depending on if in oversub)
       // and the active power limit.  We do not need to always account for oversubscription since
       // the automatic hw power brake will assert to the GPUs if there is a problem when oversub is
       // entered from the time OCC can set and GPUs react to a new power limit
       if(i_oversubscription)
       {
          // system in oversubscription use N mode cap
          l_system_gpu_total_pcap = L_n_mode_gpu_total_pcap;
       }
       else
       {
          // system is not in oversubscription use N+1 mode cap
          l_system_gpu_total_pcap = L_n_plus_1_mode_gpu_total_pcap;
       }

       L_total_gpu_pcap = (l_system_gpu_total_pcap < L_active_psr_gpu_total_pcap) ?
                           l_system_gpu_total_pcap : L_active_psr_gpu_total_pcap;

       // Divide the total equally across all GPUs in the system
       if(G_first_num_gpus_sys)
       {
          L_per_gpu_pcap = L_total_gpu_pcap / G_first_num_gpus_sys;
       }
       else
       {
           L_per_gpu_pcap = 0;
           TRAC_ERR("amec_gpu_pcap: Called with no GPUs present!");
       }
    }

    // Setup to send new power limit to GPUs. The actual sending of GPU power limit will be handled by task_gpu_sm()
    for (i=0; i<MAX_NUM_GPU_PER_DOMAIN; i++)
    {
        // Before sending a GPU a power limit the power limits must be read from the GPU to know min/max GPU allows
        if( GPU_PRESENT(i) && g_amec->gpu[i].pcap.pwr_limits_read )
        {
           l_gpu_cap_mw = L_per_gpu_pcap * 1000;  // convert W to mW

           // GPU is present and have min/max power limits from GPU
           // clip the GPU power limit to min/max GPU limit if needed
           if(l_gpu_cap_mw < g_amec->gpu[i].pcap.gpu_min_pcap_mw)  // clip to min?
           {
              l_gpu_cap_mw = g_amec->gpu[i].pcap.gpu_min_pcap_mw;
           }
           else if(l_gpu_cap_mw > g_amec->gpu[i].pcap.gpu_max_pcap_mw)  // clip to max?
           {
              l_gpu_cap_mw = g_amec->gpu[i].pcap.gpu_max_pcap_mw;
           }

           // check if this is a new power limit
           if(g_amec->gpu[i].pcap.gpu_desired_pcap_mw != l_gpu_cap_mw)
           {
              if( (g_amec->gpu[i].pcap.gpu_desired_pcap_mw != 0) ||
                  (L_last_pcap_traced[i] != l_gpu_cap_mw) )
              {
                 L_last_pcap_traced[i] = l_gpu_cap_mw;
                 TRAC_IMP("amec_gpu_pcap: Updating GPU%d desired pcap %dmW to %dmW", i,
                          g_amec->gpu[i].pcap.gpu_desired_pcap_mw, l_gpu_cap_mw);

              }

              g_amec->gpu[i].pcap.gpu_desired_pcap_mw = l_gpu_cap_mw;
           }
        }
    }  // for each GPU

    L_first_run = FALSE;
}
Beispiel #16
0
// Function Specification
//
// Name: reset_state_request
//
// Description: Request Reset States
//
// End Function Specification
void reset_state_request(uint8_t i_request)
{
  //TODO:  This needs to be changed so that G_reset_state operations are
  // atomic.

  switch(i_request)
  {
    case RESET_REQUESTED_DUE_TO_ERROR:
      // In case we want to just halt() if fw requests a reset, this is
      // the place to do it.  It is disabled by default, and there is no
      // code to eanble it.
      if( G_halt_on_reset_request )
      {
          TRAC_ERR("Halt()");

          // This isn't modeled very well in simics.  OCC will go into an
          // infinite loop, which eventually would crash Simics.
          HALT_WITH_FIR_SET;
      }

      // If we have TMGT comm, and we aren't already in reset, set the reset
      // state to reset to enter the reset state machine.
      if(G_reset_state < RESET_REQUESTED_DUE_TO_ERROR)
      {
        TRAC_IMP("Activating reset required state.");

        G_reset_state = RESET_REQUESTED_DUE_TO_ERROR;

        // Post the semaphore to wakeup the thread that
        // will put us into SAFE state.
        ssx_semaphore_post(&G_dcomThreadWakeupSem);

        // Set RTL Flags here too, depending how urgent it is that we stop
        // running tasks.
        rtl_set_run_mask(RTL_FLAG_RST_REQ);
      }
      break;

    case NOMINAL_REQUESTED_DUE_TO_ERROR:
      if(G_reset_state < NOMINAL_REQUESTED_DUE_TO_ERROR)
      {
        TRAC_ERR("Going to Nominal because of error");

        // May need to add counter if multiple places request nominal
        G_reset_state = NOMINAL_REQUESTED_DUE_TO_ERROR;

        //TODO:  Will need to set some flag or event here
      }
      break;

    case RESET_NOT_REQUESTED:
      if(G_reset_state == NOMINAL_REQUESTED_DUE_TO_ERROR)
      {
        TRAC_IMP("Clearing Nominal Reset State because of error");

        // May need to add counter check if multiple places request nominal
        G_reset_state = RESET_NOT_REQUESTED;

        //TODO:  Will need to clear some flag or event here
      }
      break;

    default:
      break;

  }
}
Beispiel #17
0
// Function Specification
//
// Name: amec_slv_freq_smh
//
// Description: Slave OCC's frequency state machine.
//              This function will run every tick.
//
// Thread: RealTime Loop
//
// Task Flags:
//
// End Function Specification
void amec_slv_freq_smh(void)
{
    /*------------------------------------------------------------------------*/
    /*  Local Variables                                                       */
    /*------------------------------------------------------------------------*/
    uint8_t     quad = 0;       // loop through quads
    uint8_t     core_num = 0;   // core ID
    uint8_t     core_idx = 0;   // loop through cores within each quad
    Pstate      pmax[MAXIMUM_QUADS] = {0}; // max pstate (min frequency) within each quad
    Pstate      pmax_chip = 0;  // highest Pstate (lowest frequency) across all quads
    bool        l_atLeast1Core[MAXIMUM_QUADS] = {FALSE};  // at least 1 core present and online in quad
    bool        l_atLeast1Quad = FALSE;    // at least 1 quad online
    static bool L_mfg_set_trace[MAXIMUM_QUADS] = {FALSE};
    static bool L_mfg_clear_trace[MAXIMUM_QUADS] = {FALSE};

    /*------------------------------------------------------------------------*/
    /*  Code                                                                  */
    /*------------------------------------------------------------------------*/

    // loop through all quads, get f_requests, translate to pstates and determine pmax across chip
    for (quad = 0; quad < MAXIMUM_QUADS; quad++)
    {
        for (core_idx=0; core_idx<NUM_CORES_PER_QUAD; core_idx++)  // loop thru all cores in quad
        {
            core_num = (quad*NUM_CORES_PER_QUAD) + core_idx;

            // ignore core if freq request is 0 (core not present when amec_slv_proc_voting_box ran)
            if(g_amec->proc[0].core[core_num].f_request != 0)
            {
               l_atLeast1Core[quad] = TRUE;
               l_atLeast1Quad = TRUE;
               // The higher the pstate number, the lower the frequency
               if(pmax[quad] <  proc_freq2pstate(g_amec->proc[0].core[core_num].f_request))
               {
                   pmax[quad] = proc_freq2pstate(g_amec->proc[0].core[core_num].f_request);
                   if(pmax_chip < pmax[quad])  // check if this is a new lowest freq for the chip
                      pmax_chip = pmax[quad];
               }
            }
        }
    }

    // Skip determining new frequency if all cores in all quads are offline
    if(l_atLeast1Quad)
    {
        // check for mfg quad Pstate request and set Pstate for each quad
        for (quad = 0; quad < MAXIMUM_QUADS; quad++)
        {
            // set quad with no cores present to lowest frequency for the chip
            if(l_atLeast1Core[quad] == FALSE)
               pmax[quad] = pmax_chip;

            // check if there is a mnfg Pstate request for this quad
            if(g_amec->mnfg_parms.quad_pstate[quad] != 0xFF)
            {
               // use mnfg request if it is a lower frequency (higher pState)
               if(g_amec->mnfg_parms.quad_pstate[quad] > pmax[quad])
                  pmax[quad] = g_amec->mnfg_parms.quad_pstate[quad];

               if(L_mfg_clear_trace[quad] == FALSE)
                  L_mfg_set_trace[quad] = TRUE;
            }
            else if(L_mfg_clear_trace[quad] == TRUE)
            {
                TRAC_INFO("amec_slv_freq_smh: mfg Quad %d Pstate request cleared. New Pstate = 0x%02x", quad, pmax[quad]);
                L_mfg_clear_trace[quad] = FALSE;
            }

#ifdef PROC_DEBUG
            if (G_desired_pstate[quad] != pmax[quad])
            {
                TRAC_IMP("Updating Quad %d's Pstate to %d", quad, pmax[quad]);
            }
#endif
            // update quad pstate request
            G_desired_pstate[quad] = pmax[quad];

            if(L_mfg_set_trace[quad] == TRUE)
            {
                TRAC_INFO("amec_slv_freq_smh: mfg Quad %d Pstate request set = 0x%02x", quad, pmax[quad]);
                L_mfg_set_trace[quad] = FALSE;
                L_mfg_clear_trace[quad] = TRUE;
            }
        }
    }  // if at least 1 core online
}
Beispiel #18
0
void cent_update_nlimits(uint32_t i_cent)
{
    /*------------------------------------------------------------------------*/
    /*  Local Variables                                                       */
    /*------------------------------------------------------------------------*/
    static uint32_t L_trace_throttle_count = 0;
    uint16_t l_mba01_mba_maxn, l_mba01_chip_maxn, l_mba23_mba_maxn, l_mba23_chip_maxn;
    /*------------------------------------------------------------------------*/
    /*  Code                                                                  */
    /*------------------------------------------------------------------------*/

    do
    {
        centaur_throttle_t* l_active_limits01 =
            &G_centaurThrottleLimits[i_cent][0];
        centaur_throttle_t* l_active_limits23 =
            &G_centaurThrottleLimits[i_cent][1];
        mem_throt_config_data_t* l_state_limits01 =
            &G_sysConfigData.mem_throt_limits[i_cent][0];
        mem_throt_config_data_t* l_state_limits23 =
            &G_sysConfigData.mem_throt_limits[i_cent][1];

        //Minimum N value is not state dependent
        l_active_limits01->min_n_per_mba = l_state_limits01->min_ot_n_per_mba;
        l_active_limits23->min_n_per_mba = l_state_limits23->min_ot_n_per_mba;

        //oversubscription?
        if(AMEC_INTF_GET_OVERSUBSCRIPTION())
        {
            l_mba01_mba_maxn = l_state_limits01->ovs_n_per_mba;
            l_mba01_chip_maxn = l_state_limits01->ovs_n_per_chip;
            l_mba23_mba_maxn = l_state_limits23->ovs_n_per_mba;
            l_mba23_chip_maxn = l_state_limits23->ovs_n_per_chip;
        }
        else if(CURRENT_MODE() == OCC_MODE_NOMINAL)
        {
            l_mba01_mba_maxn = l_state_limits01->nom_n_per_mba;
            l_mba01_chip_maxn = l_state_limits01->nom_n_per_chip;
            l_mba23_mba_maxn = l_state_limits23->nom_n_per_mba;
            l_mba23_chip_maxn = l_state_limits23->nom_n_per_chip;
        }
        else //DPS, TURBO, FFO, and SPS modes will use these settings
        {
            l_mba01_mba_maxn = l_state_limits01->turbo_n_per_mba;
            l_mba01_chip_maxn = l_state_limits01->turbo_n_per_chip;
            l_mba23_mba_maxn = l_state_limits23->turbo_n_per_mba;
            l_mba23_chip_maxn = l_state_limits23->turbo_n_per_chip;
        }

        l_active_limits01->max_n_per_chip = l_mba01_chip_maxn;
        l_active_limits23->max_n_per_chip = l_mba23_chip_maxn;

        //Trace when the MBA max N value changes
        if((l_mba01_mba_maxn != l_active_limits01->max_n_per_mba) ||
           (l_mba23_mba_maxn != l_active_limits23->max_n_per_mba))
        {
            l_active_limits01->max_n_per_mba = l_mba01_mba_maxn;
            l_active_limits23->max_n_per_mba = l_mba23_mba_maxn;

            //Don't trace every MBA changing, just one
            if(!L_trace_throttle_count)
            {
                L_trace_throttle_count = CENT_TRACE_THROTTLE_DELAY;
                TRAC_IMP("New MBA throttle max|min N values: mba01[0x%08x], mba23[0x%08x]",
                        (uint32_t)((l_mba01_mba_maxn << 16) | l_active_limits01->min_n_per_mba),
                        (uint32_t)((l_mba23_mba_maxn << 16) | l_active_limits23->min_n_per_mba));
                break;
            }
        }

        if(L_trace_throttle_count)
        {
            L_trace_throttle_count--;
        }

    }while(0);
}
Beispiel #19
0
//////////////////////////
// Function Specification
//
// Name: amec_pcap_calc
//
// Description: Calculate the node, memory and processor power caps.
//
// Thread: Real Time Loop
//
// End Function Specification
void amec_pcap_calc(const bool i_oversub_state)
{
    bool l_active_pcap_changed = FALSE;
    uint16_t l_node_pwr = AMECSENSOR_PTR(PWRSYS)->sample;
    uint16_t l_p0_pwr   = AMECSENSOR_PTR(PWRPROC)->sample;
    int32_t l_avail_power = 0;
    uint16_t mem_pwr_diff = 0;
    uint32_t l_proc_fraction = 0;
    static uint32_t L_prev_node_pcap = 0;
    static bool L_apss_error_traced = FALSE;
    static uint32_t L_ticks_mem_pwr_available = 0;
    static bool L_trace_pcap_throttle = true;
    static bool L_trace_pcap_unthrottle = true;

    // Determine the active power cap.
    // when in oversub (N mode) only use oversub pcap if lower than user set pcap
    // OCC should allow N mode to be higher than N+1 (don't compare against norm_node_pcap)
    // N mode may be higher on some systems due to ps issue reporting higher power in N mode
    if( (TRUE == i_oversub_state) &&
        (g_amec->pcap.ovs_node_pcap < G_sysConfigData.pcap.current_pcap) )
    {
        g_amec->pcap.active_node_pcap = g_amec->pcap.ovs_node_pcap;
    }
    // norm_node_pcap is set as lowest between sys (N+1 mode) and
    // user in amec_data_write_pcap()
    else
    {
        g_amec->pcap.active_node_pcap = g_amec->pcap.norm_node_pcap;
    }

    //Trace whenever the node pcap changes
    if(L_prev_node_pcap != g_amec->pcap.active_node_pcap)
    {
        TRAC_IMP("amec_pcap_calc: Node pcap set to %d watts.",
                  g_amec->pcap.active_node_pcap);
        L_prev_node_pcap = g_amec->pcap.active_node_pcap;

        // set this pcap as valid (needed by master for comparison)
        g_amec->pcap_valid = 1;
        l_active_pcap_changed = TRUE;
    }

    l_avail_power = g_amec->pcap.active_node_pcap - l_node_pwr;

    // Determine GPU power cap if there are GPUs present
    if(G_first_proc_gpu_config)
    {
       amec_gpu_pcap(i_oversub_state, l_active_pcap_changed, l_avail_power);
    }

    if(l_node_pwr != 0)
    {
        l_proc_fraction = ((uint32_t)(l_p0_pwr) << 16)/l_node_pwr;
        if(L_apss_error_traced)
        {
            TRAC_ERR("PCAP: PWRSYS sensor is no longer 0.");
            L_apss_error_traced = FALSE;
        }

        // check if allowed to increase power AND memory throttled due to pcap
        if((l_avail_power > 0) && (g_amec->pcap.active_mem_level != 0))
        {
            // un-throttle memory if there is enough available power between
            // current and new throttles
            if (CURRENT_MODE() == OCC_MODE_NOMINAL)
            {
                mem_pwr_diff = g_amec->pcap.nominal_mem_pwr;
            }
            else
            {
                mem_pwr_diff = g_amec->pcap.turbo_mem_pwr;
            }

            // currently there's only 1 mem pcap throt level so must be pcap1
            mem_pwr_diff -= g_amec->pcap.pcap1_mem_pwr;

            if(l_avail_power >= mem_pwr_diff)
            {
                L_ticks_mem_pwr_available++;

                if( L_ticks_mem_pwr_available == UNTHROTTLE_MEMORY_DELAY )
                {
                    if( L_trace_pcap_unthrottle ||
                       (G_allow_trace_flags & ALLOW_MEM_TRACE) )
                    {
                        TRAC_IMP("PCAP: Un-Throttling memory");
                        L_trace_pcap_unthrottle = false;
                    }
                    g_amec->pcap.active_mem_level = 0;
                    L_ticks_mem_pwr_available = 0;
                    // don't let the proc have any available power this tick
                    l_avail_power = 0;
                }
            }
        }
        // check if need to reduce power and frequency is already at the min
        else if(l_avail_power < 0)
        {
            L_ticks_mem_pwr_available = 0;

            // if memory is not throttled and frequency is at min shed additional power
            // by throttling memory
            if( (g_amec->pcap.active_mem_level == 0) &&
                (g_amec->proc[0].pwr_votes.ppb_fmax == g_amec->sys.fmin) )
            {
                if( L_trace_pcap_throttle ||
                   (G_allow_trace_flags & ALLOW_MEM_TRACE) )
                {
                    TRAC_IMP("PCAP: Throttling memory");
                    L_trace_pcap_throttle = false;
                }
                g_amec->pcap.active_mem_level = 1;
            }
        }
        else
        {
            // no changes to memory throttles due to power
        }
    }
    else
    {
        if(!L_apss_error_traced)
        {
            TRAC_ERR("PCAP: PWRSYS sensor is showing a value of 0.");
            L_apss_error_traced = TRUE;
        }
    }

    // skip processor changes until memory is un-capped
    if(!g_amec->pcap.active_mem_level)
    {
        g_amec->pcap.active_proc_pcap = l_p0_pwr + ((l_proc_fraction * l_avail_power) >> 16);

        //NOTE: Power capping will not affect nominal cores unless a customer pcap
        //      is set below the max pcap or oversubscription occurs.  However,
        //      nominal cores will drop below nominal if ppb_fmax drops below nominal
        if(g_amec->pcap.active_node_pcap < G_sysConfigData.pcap.max_pcap)
        {
           g_amec->proc[0].pwr_votes.nom_pcap_fmin = G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY];
        }
        else
        {
           g_amec->proc[0].pwr_votes.nom_pcap_fmin = G_sysConfigData.sys_mode_freq.table[OCC_MODE_NOMINAL];
        }
    }
Beispiel #20
0
void task_core_data( task_t * i_task )
{

    errlHndl_t  l_err = NULL;       //Error handler
    tracDesc_t  l_trace = NULL;     //Temporary trace descriptor
    int         rc = 0;     //return code
    bulk_core_data_task_t * l_bulk_core_data_ptr = (bulk_core_data_task_t *)i_task->data_ptr;
    GpeGetCoreDataParms * l_parms = (GpeGetCoreDataParms *)(l_bulk_core_data_ptr->gpe_req.parameter);
    gpe_bulk_core_data_t  * l_temp = NULL;

    do
    {
        //First, check to see if the previous GPE request still running
        //A request is considered idle if it is not attached to any of the
        //asynchronous request queues
        if( !(async_request_is_idle(&l_bulk_core_data_ptr->gpe_req.request)) )
        {
            //This should not happen unless there's a problem
            //Trace 1 time
            if( !G_queue_not_idle_traced )
            {
                TRAC_ERR("Core data GPE is still running \n");
                G_queue_not_idle_traced = TRUE;
            }
            break;
        }

        //Need to complete collecting data for all assigned cores from previous interval
        //and tick 0 is the current tick before collect data again.
        if( (l_bulk_core_data_ptr->current_core == l_bulk_core_data_ptr->end_core)
            &&
            ((CURRENT_TICK & (MAX_NUM_TICKS - 1)) != 0) )
        {
            PROC_DBG("Not collect data. Need to wait for tick.\n");
            break;
        }

        //Check to see if the previously GPE request has successfully completed
        //A request is not considered complete until both the engine job
        //has finished without error and any callback has run to completion.

        if( async_request_completed(&l_bulk_core_data_ptr->gpe_req.request)
            &&
            CORE_PRESENT(l_bulk_core_data_ptr->current_core) )
        {
            //If the previous GPE request succeeded then swap core_data_ptr
            //with the global one. The gpe routine will write new data into
            //a buffer that is not being accessed by the RTLoop code.

            PROC_DBG( "Swap core_data_ptr [%x] with the global one\n",
                     l_bulk_core_data_ptr->current_core );

            //debug only
#ifdef PROC_DEBUG
            print_core_status(l_bulk_core_data_ptr->current_core);
            print_core_data_sensors(l_bulk_core_data_ptr->current_core);
#endif

            l_temp = l_bulk_core_data_ptr->core_data_ptr;
            l_bulk_core_data_ptr->core_data_ptr =
                    G_core_data_ptrs[l_bulk_core_data_ptr->current_core];
            G_core_data_ptrs[l_bulk_core_data_ptr->current_core] = l_temp;

            //Core data has been collected so set the bit in global mask.
            //AMEC code will know which cores to update sensors for. AMEC is
            //responsible for clearing the bit later on.
            G_updated_core_mask |= CORE0_PRESENT_MASK >> (l_bulk_core_data_ptr->current_core);

            // Presumptively clear the empath error mask
            G_empath_error_core_mask &=
                    ~(CORE0_PRESENT_MASK >> (l_bulk_core_data_ptr->current_core));

            // The gpe_data collection code has to handle the workaround for
            // HW280375.  Two new flags have been added to the OHA_RO_STATUS_REG
            // image to indicate whether the EMPATH collection failed, and
            // whether it was due to an "expected" error that we can ignore
            // (we can ignore the data as well), or an "unexpected" error that
            // we will create an informational log one time.
            //
            // The "expected" errors are very rare in practice, in fact we may
            // never even see them unless running a specific type of workload.
            // If you want to test the handling of expected errors compile the
            // GPE code with -DINJECT_HW280375_ERRORS which will inject an error
            // approximately every 1024 samples
            //
            // To determine if the expected error has occurred inspect the
            // CoreDataOha element of the CoreData structure written by the GPE
            // core data job.  The OHA element contains the oha_ro_status_reg.
            // Inside the OHA status register is a 16 bit reserved field.
            // gpe_data.h defines two masks that can be applied against the
            // reserved field to check for these errors:
            // CORE_DATA_EXPECTED_EMPATH_ERROR
            // CORE_DATA_UNEXPECTED_EMPATH_ERROR
            // Also, a 4-bit PCB parity + error code is saved at bit position:
            // CORE_DATA_EMPATH_ERROR_LOCATION, formally the length is
            // specified by: CORE_DATA_EMPATH_ERROR_BITS
            gpe_bulk_core_data_t *l_core_data =
                    G_core_data_ptrs[l_bulk_core_data_ptr->current_core];

            // We will trace the errors, but only a certain number of
            // times, we will only log the unexpected error once.
#define OCC_EMPATH_ERROR_THRESH 10
            static uint32_t L_expected_emp_err_cnt = 0;
            static uint32_t L_unexpected_emp_err_cnt = 0;

            // Check the reserved field for the expected or the unexpected error flag
            if ((l_core_data->oha.oha_ro_status_reg.fields._reserved0 & CORE_DATA_EXPECTED_EMPATH_ERROR)
                ||
                (l_core_data->oha.oha_ro_status_reg.fields._reserved0 & CORE_DATA_UNEXPECTED_EMPATH_ERROR))
            {
                // Indicate empath error on current core
                G_empath_error_core_mask |=
                        CORE0_PRESENT_MASK >> (l_bulk_core_data_ptr->current_core);

                // Save the high and low order words of the OHA status reg
                uint32_t l_oha_reg_high = l_core_data->oha.oha_ro_status_reg.words.high_order;
                uint32_t l_oha_reg_low = l_core_data->oha.oha_ro_status_reg.words.low_order;

                // Handle each error case
                if ((l_core_data->oha.oha_ro_status_reg.fields._reserved0 & CORE_DATA_EXPECTED_EMPATH_ERROR)
                    &&
                    (L_expected_emp_err_cnt < OCC_EMPATH_ERROR_THRESH))
                {
                    L_expected_emp_err_cnt++;
                    TRAC_IMP("Expected empath collection error occurred %d time(s)! Core = %d",
                             L_expected_emp_err_cnt,
                             l_bulk_core_data_ptr->current_core);
                    TRAC_IMP("OHA status register: 0x%4.4x%4.4x",
                             l_oha_reg_high, l_oha_reg_low);
                }

                if ((l_core_data->oha.oha_ro_status_reg.fields._reserved0 & CORE_DATA_UNEXPECTED_EMPATH_ERROR)
                    &&
                    (L_unexpected_emp_err_cnt < OCC_EMPATH_ERROR_THRESH))
                {
                    L_unexpected_emp_err_cnt++;
                    TRAC_ERR("Unexpected empath collection error occurred %d time(s)! Core = %d",
                             L_unexpected_emp_err_cnt,
                             l_bulk_core_data_ptr->current_core);
                    TRAC_ERR("OHA status register: 0x%4.4x%4.4x",
                             l_oha_reg_high, l_oha_reg_low);

                    // Create and commit an informational error the first
                    // time this occurs.
                    if (L_unexpected_emp_err_cnt == 1)
                    {
                        TRAC_IMP("Logging unexpected empath collection error 1 time only.");
                        /*
                        * @errortype
                        * @moduleid    PROC_TASK_CORE_DATA_MOD
                        * @reasoncode  INTERNAL_HW_FAILURE
                        * @userdata1   OHA status reg high
                        * @userdata2   OHA status reg low
                        * @userdata4   ERC_PROC_CORE_DATA_EMPATH_ERROR
                        * @devdesc     An unexpected error occurred while
                        *              collecting core empath data.
                        */
                        l_err = createErrl(
                                PROC_TASK_CORE_DATA_MOD, //modId
                                INTERNAL_HW_FAILURE,     //reason code
                                ERC_PROC_CORE_DATA_EMPATH_ERROR, //Extended reason code
                                ERRL_SEV_INFORMATIONAL,  //Severity
                                NULL,                    //Trace
                                DEFAULT_TRACE_SIZE,      //Trace Size
                                l_oha_reg_high,          //userdata1
                                l_oha_reg_low);          //userdata2

                        commitErrl(&l_err);
                    }
                }
            }
        }
Beispiel #21
0
// Function Specification
//
// Name: amec_slv_proc_voting_box
//
// Description: Slave OCC's voting box that decides the frequency request.
//              This function will run every tick.
//
// Thread: RealTime Loop
//
// Task Flags:
//
// End Function Specification
void amec_slv_proc_voting_box(void)
{
    /*------------------------------------------------------------------------*/
    /*  Local Variables                                                       */
    /*------------------------------------------------------------------------*/
    uint16_t                        k = 0;
    uint16_t                        l_chip_fmax = g_amec->sys.fmax;
    uint16_t                        l_core_freq = 0;
    uint16_t                        l_core_freq_max = 0;  // max freq across all cores
    uint16_t                        l_core_freq_min = g_amec->sys.fmax;  // min freq across all cores
    uint32_t                        l_current_reason = 0;  // used for debug purposes
    static uint32_t                 L_last_reason = 0;     // used for debug purposes
    uint32_t                        l_chip_reason = 0;
    uint32_t                        l_core_reason = 0;
    amec_proc_voting_reason_t       l_kvm_throt_reason = NO_THROTTLE;
    amec_part_t                     *l_part = NULL;

    // frequency threshold for reporting throttling
    uint16_t l_report_throttle_freq = G_sysConfigData.system_type.report_dvfs_nom ?  G_sysConfigData.sys_mode_freq.table[OCC_MODE_NOMINAL] : G_sysConfigData.sys_mode_freq.table[OCC_MODE_TURBO];

    /*------------------------------------------------------------------------*/
    /*  Code                                                                  */
    /*------------------------------------------------------------------------*/
    if (!G_allowPstates)
    {
        // Don't allow pstates to be sent until after initial mode has been set
        if ( (CURRENT_MODE()) || (G_sysConfigData.system_type.kvm) )
        {
            G_allowPstates = TRUE;
        }
    }

    // Voting Box for CPU speed.
    // This function implements the voting box to decide which input gets the right
    // to actuate the system.

    // check for oversubscription if redundant ps policy (oversubscription) is being enforced
    if (G_sysConfigData.system_type.non_redund_ps == false)
    {
        // If in oversubscription and there is a defined (non 0) OVERSUB frequency less than max then use it
        if( (AMEC_INTF_GET_OVERSUBSCRIPTION()) &&
            (G_sysConfigData.sys_mode_freq.table[OCC_MODE_OVERSUB]) &&
            (G_sysConfigData.sys_mode_freq.table[OCC_MODE_OVERSUB] < l_chip_fmax) )
        {
            l_chip_fmax = G_sysConfigData.sys_mode_freq.table[OCC_MODE_OVERSUB];
            l_chip_reason = AMEC_VOTING_REASON_OVERSUB;
        }
    }

    // If there is an active VRM fault and a defined (non 0) VRM N frequency less than max use it
    if( (g_amec->sys.vrm_fault_status) &&
        (G_sysConfigData.sys_mode_freq.table[OCC_MODE_VRM_N]) &&
        (G_sysConfigData.sys_mode_freq.table[OCC_MODE_VRM_N] < l_chip_fmax) )
    {
        l_chip_fmax = G_sysConfigData.sys_mode_freq.table[OCC_MODE_VRM_N];
        l_chip_reason = AMEC_VOTING_REASON_VRM_N;
    }

    // PPB_FMAX
    if(g_amec->proc[0].pwr_votes.ppb_fmax < l_chip_fmax)
    {
        l_chip_fmax = g_amec->proc[0].pwr_votes.ppb_fmax;
        l_chip_reason = AMEC_VOTING_REASON_PPB;

        if(l_report_throttle_freq <= l_chip_fmax)
        {
            l_kvm_throt_reason = PCAP_EXCEED_REPORT;
        }
        else
        {
            l_kvm_throt_reason = POWERCAP;
        }
    }

    // PMAX_CLIP_FREQ
    if(g_amec->proc[0].pwr_votes.pmax_clip_freq < l_chip_fmax)
    {
        l_chip_fmax = g_amec->proc[0].pwr_votes.pmax_clip_freq;
        l_chip_reason = AMEC_VOTING_REASON_PMAX;
        l_kvm_throt_reason = POWER_SUPPLY_FAILURE;
    }

    // Pmax_clip frequency request if there is an APSS failure
    if(g_amec->proc[0].pwr_votes.apss_pmax_clip_freq < l_chip_fmax)
    {
        l_chip_fmax = g_amec->proc[0].pwr_votes.apss_pmax_clip_freq;
        l_chip_reason = AMEC_VOTING_REASON_APSS_PMAX;
        l_kvm_throt_reason = POWER_SUPPLY_FAILURE;
    }

    //THERMALPROC.FREQ_REQUEST
    //Thermal controller input based on processor temperature
    if(g_amec->thermalproc.freq_request < l_chip_fmax)
    {
        l_chip_fmax = g_amec->thermalproc.freq_request;
        l_chip_reason = AMEC_VOTING_REASON_PROC_THRM;

        if( l_report_throttle_freq <= l_chip_fmax)
        {
            l_kvm_throt_reason = PROC_OVERTEMP_EXCEED_REPORT;
        }
        else
        {
            l_kvm_throt_reason = CPU_OVERTEMP;
        }
    }

    //Thermal controller input based on VRM Vdd temperature
    if(g_amec->thermalvdd.freq_request < l_chip_fmax)
    {
        l_chip_fmax = g_amec->thermalvdd.freq_request;
        l_chip_reason = AMEC_VOTING_REASON_VDD_THRM;

        if( l_report_throttle_freq <= l_chip_fmax)
        {
            l_kvm_throt_reason = VDD_OVERTEMP_EXCEED_REPORT;
        }
        else
        {
            l_kvm_throt_reason = VDD_OVERTEMP;
        }
    }

    for (k=0; k<MAX_NUM_CORES; k++)
    {
        if( CORE_PRESENT(k) && !CORE_OFFLINE(k) )
        {
            l_core_freq = l_chip_fmax;
            l_core_reason = l_chip_reason;

            // Disable DPS in KVM
            if(!G_sysConfigData.system_type.kvm)
            {
                l_part = amec_part_find_by_core(&g_amec->part_config, k);

                // Check frequency request generated by DPS algorithms
                if(g_amec->proc[0].core[k].core_perf.dps_freq_request < l_core_freq)
                {
                    l_core_freq = g_amec->proc[0].core[k].core_perf.dps_freq_request;
                    l_core_reason = AMEC_VOTING_REASON_UTIL;
                }

                // Adjust frequency based on soft frequency boundaries
                if(l_part != NULL)
                {
                    if(l_core_freq < l_part->soft_fmin)
                    {
                        // Before enforcing a soft Fmin, make sure we don't
                        // have a thermal or power emergency
                        if(!(l_chip_reason & (AMEC_VOTING_REASON_PROC_THRM |
                                              AMEC_VOTING_REASON_VDD_THRM |
                                              AMEC_VOTING_REASON_PPB |
                                              AMEC_VOTING_REASON_PMAX |
                                              AMEC_VOTING_REASON_CONN_OC)))
                        {
                            l_core_freq = l_part->soft_fmin;
                            l_core_reason = AMEC_VOTING_REASON_SOFT_MIN;
                        }
                    }
                    else if(l_core_freq > l_part->soft_fmax)
                    {
                        l_core_freq = l_part->soft_fmax;
                        l_core_reason = AMEC_VOTING_REASON_SOFT_MAX;
                    }
                }
            }

            if(CURRENT_MODE() == OCC_MODE_NOMINAL)
            {
                // PROC_PCAP_NOM_VOTE
                if(g_amec->proc[0].pwr_votes.proc_pcap_nom_vote < l_core_freq)
                {
                    l_core_freq = g_amec->proc[0].pwr_votes.proc_pcap_nom_vote;
                    l_core_reason = AMEC_VOTING_REASON_PWR;
                    l_kvm_throt_reason = POWERCAP;
                }
            }
            else
            {
                // PROC_PCAP_VOTE
                if(g_amec->proc[0].pwr_votes.proc_pcap_vote < l_core_freq)
                {
                    l_core_freq = g_amec->proc[0].pwr_votes.proc_pcap_vote;
                    l_core_reason = AMEC_VOTING_REASON_PWR;

                    if(l_report_throttle_freq <= l_core_freq)
                    {
                        l_kvm_throt_reason = PCAP_EXCEED_REPORT;
                    }
                    else
                    {
                        l_kvm_throt_reason = POWERCAP;
                    }
                }
            }

            // Check IPS frequency request sent by Master OCC
            if(g_amec->slv_ips_freq_request != 0)
            {
                if(g_amec->slv_ips_freq_request < l_core_freq)
                {
                    l_core_freq = g_amec->slv_ips_freq_request;
                    l_core_reason = AMEC_VOTING_REASON_IPS;
                }
            }

            // Override frequency with request from Master OCC
            if(g_amec->foverride_enable)
            {
                if(g_amec->foverride != 0)
                {
                    // Override the frequency on all cores if Master OCC sends
                    // a non-zero request
                    l_core_freq = g_amec->foverride;
                    l_core_reason = AMEC_VOTING_REASON_OVERRIDE;
                }

                l_kvm_throt_reason = MANUFACTURING_OVERRIDE;
            }

            if(g_amec->pstate_foverride_enable)
            {
                if(g_amec->pstate_foverride != 0)
                {
                    // Override the frequency on all cores if the Global Pstate
                    // table has been modified
                    l_core_freq = g_amec->pstate_foverride;
                    l_core_reason = AMEC_VOTING_REASON_OVERRIDE;
                }
            }

            //Make sure the frequency is not less then the system min
            if(l_core_freq < g_amec->sys.fmin)
            {
                l_core_freq = g_amec->sys.fmin;
            }

            // Override frequency via Amester parameter interface
            if (g_amec->proc[0].parm_f_override_enable &&
                g_amec->proc[0].parm_f_override[k] > 0)
            {
                l_core_freq = g_amec->proc[0].parm_f_override[k];
                l_core_reason = AMEC_VOTING_REASON_OVERRIDE_CORE;
            }

            //STORE core frequency and reason
            g_amec->proc[0].core[k].f_request = l_core_freq;
            g_amec->proc[0].core[k].f_reason = l_core_reason;
            if(l_core_freq < l_core_freq_min)
            {
                // store the new lowest frequency and reason to be used after all cores checked
                l_core_freq_min = l_core_freq;
                l_current_reason = l_core_reason;
            }

            // Update the Amester parameter telling us the reason. Needed for
            // parameter array.
            g_amec->proc[0].parm_f_reason[k] = l_core_reason;

            //CURRENT_MODE() may be OCC_MODE_NOCHANGE because STATE change is processed
            //before MODE change
            if ((CURRENT_MODE() != OCC_MODE_DYN_POWER_SAVE)    &&
                (CURRENT_MODE() != OCC_MODE_DYN_POWER_SAVE_FP) &&
                (CURRENT_MODE() != OCC_MODE_NOM_PERFORMANCE)   &&
                (CURRENT_MODE() != OCC_MODE_MAX_PERFORMANCE)   &&
                (CURRENT_MODE() != OCC_MODE_FMF)               &&
                (CURRENT_MODE() != OCC_MODE_NOCHANGE)          &&
                (l_core_reason & NON_DPS_POWER_LIMITED))
            {
                G_non_dps_power_limited = TRUE;
            }
            else
            {
                G_non_dps_power_limited = FALSE;
            }

            // Update the sensor telling us what the requested frequency is
            sensor_update( AMECSENSOR_ARRAY_PTR(FREQREQC0,k),
                    (uint16_t) g_amec->proc[0].core[k].f_request);

#if DEBUG_PROC_VOTING_BOX
            /// This trace that can be used to debug the voting
            /// box and control loops.  It will trace the reason why a
            /// controller is lowering the freq, but will only do it once in a
            /// row for the specific freq it wants to control to.  It assumes
            /// that all cores will be controlled to same freq.
            if(l_chip_fmax != g_amec->sys.fmax){
                static uint16_t L_trace = 0;
                if(l_chip_fmax != L_trace){
                    L_trace = l_chip_fmax;
                    TRAC_INFO("Core: %d, Freq: %d, Reason: %d",k,l_core_freq,l_core_reason);
                }
            }
#endif

            if(l_core_freq > l_core_freq_max)
            {
                l_core_freq_max = l_core_freq;
            }
        } // if core present and not offline
        else
        {
            //Set f_request to 0 so this core is ignored in amec_slv_freq_smh()
            g_amec->proc[0].core[k].f_request = 0;
            g_amec->proc[0].core[k].f_reason = 0;
        }
    }//End of for loop

    // update max core frequency if not 0 i.e. all cores offline (stop 2 or greater)
    // this is used by power capping alg, updating to 0 will cause power throttling when not needed
    if(l_core_freq_max)
    {
        g_amec->proc[0].core_max_freq = l_core_freq_max;
        // update the overall reason driving frequency across all cores
        g_amec->proc[0].f_reason = l_current_reason;
    }

    //check if there was a throttle reason change
    if(l_kvm_throt_reason != G_amec_opal_proc_throt_reason)
    {
        //Always update G_amec_opal_proc_throt_reason, this is used to set poll rsp bits for all system types
        G_amec_opal_proc_throt_reason = l_kvm_throt_reason;

        // Only if running OPAL need to notify dcom thread to update the table in HOMER for OPAL
        if(G_sysConfigData.system_type.kvm)
        {
            ssx_semaphore_post(&G_dcomThreadWakeupSem);
        }
    }
    // For debug... if lower than max update vars returned in poll response to give clipping reason
    g_amec->proc[0].core_min_freq = l_core_freq_min;
    if(l_core_freq_min < g_amec->sys.fmax)
    {
        if(l_current_reason == L_last_reason)
        {
            // same reason INC counter
            if(g_amec->proc[0].current_clip_count != 0xFF)
            {
                 g_amec->proc[0].current_clip_count++;
            }
        }
        else
        {
            // new reason update history and set counter to 1
            L_last_reason = l_current_reason;
            g_amec->proc[0].current_clip_count = 1;
            if( (g_amec->proc[0].chip_f_reason_history & l_current_reason) == 0)
            {
                g_amec->proc[0].chip_f_reason_history |= l_current_reason;
                TRAC_IMP("First time throttling for reason[0x%08X] History[0x%08X] freq = %d",
                          l_current_reason, g_amec->proc[0].chip_f_reason_history, l_core_freq_min);
            }
        }
    }
    else // no active clipping
    {
        L_last_reason = 0;
        g_amec->proc[0].current_clip_count = 0;
    }
}