import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_irq_handlers.c
//
//  p9_pgpe_irq_handler_cme_err
//
//  Handles CME error interrupt which is pcb type5 interrupt
//
// Take immediate action here since Pstates cannot be moved using the faulted
// CMEs per normal protocols.  The remainder of the actions in response to this error
// occur after going into safe mode
//
p9_pgpe_irq_handler_cme_err
Handles CME error interrupt which is pcb type5 interrupt

Take immediate action here since Pstates cannot be moved using the faulted
CMEs per normal protocols.  The remainder of the actions in response to this error
occur after going into safe mode
p9_pgpe_irq_handler_cme_err Handles CME error interrupt which is pcb type5 interrupt Take immediate action here since Pstates cannot be moved using the faulted CMEs per normal protocols . The remainder of the actions in response to this error occur after going into safe mode
void p9_pgpe_irq_handler_cme_err()
{
    uint32_t c, q, idx, idx_off, freq_done;
    uint32_t opit5pr;
    uint32_t opit5prQuad;
    uint64_t value, baseVal, coreSsh;
    qppm_dpll_freq_t dpllFreq;
    ocb_qcsr_t qcsr;
    qcsr.value = in32(G_OCB_QCSR);
    uint64_t cme_flags = 0;
    G_pgpe_optrace_data.word[0] = (G_pgpe_pstate_record.activeQuads << 24) |
                                  (G_pgpe_pstate_record.activeCores << 8);
    G_pgpe_optrace_data.word[1] = (G_pgpe_pstate_record.psCurr.fields.glb << 24) |
                                  (G_pgpe_pstate_record.extVrmCurr << 8) |
                                  PGPE_OP_TRACE_CME_FAULT;
    p9_pgpe_optrace(SEVERE_FAULT_DETECTED);
    PGPE_OPTIONAL_TRACE_AND_PANIC(PGPE_CME_FAULT); 
    opit5pr = in32(OCB_OPIT5PRA);
    out32(OCB_OPIT5PRA_CLR, opit5pr);
    PK_TRACE_INF("CER:CME ERR opit5pr 0x%x", opit5pr);
    if (!(in32(G_OCB_OCCFLG) & BIT32(PGPE_PROLONGED_DROOP_WORKAROUND_ACTIVE)))
    {
        p9_pgpe_pstate_write_core_throttle(CORE_IFU_THROTTLE, RETRY);
    }
    for (q = 0; q < MAX_QUADS; q++)
    {
        opit5prQuad = (opit5pr >> ((MAX_QUADS - q + 1) << 2)) & 0xf;
        if (opit5prQuad)
        {
            G_pgpe_pstate_record.errorQuads |= QUAD_MASK(q);
            PK_TRACE_INF("CER:Quad[%d]", q);
            if (qcsr.fields.ex_config & QUAD_EX0_MASK(q))
            {
                GPE_PUTSCOM(GPE_SCOM_ADDR_CME(CME_SCOM_XIXCR, q, 0), BIT64(3)); 
                GPE_GETSCOM(GPE_SCOM_ADDR_CME(CME_SCOM_FLAGS, q, 0), cme_flags);
            }
            if (qcsr.fields.ex_config & QUAD_EX1_MASK(q))
            {
                GPE_PUTSCOM(GPE_SCOM_ADDR_CME(CME_SCOM_XIXCR, q, 1), BIT64(3)); 
                if (!(qcsr.fields.ex_config & QUAD_EX0_MASK(q)))
                {
                    GPE_GETSCOM(GPE_SCOM_ADDR_CME(CME_SCOM_FLAGS, q, 1), cme_flags);
                }
            }
            for (c = 0; c < CORES_PER_QUAD; c++)
            {
                GPE_GETSCOM_VAR(PPM_SSHSRC, CORE_ADDR_BASE, ((q << 2) + c), 0, coreSsh);
                if (!(coreSsh & BIT64(0)))
                {
                    GPE_PUTSCOM(GPE_SCOM_ADDR_CME(CME_SCOM_LMCR_CLR, q, ((c & 2) >> 1)), (BIT64(12) >> (c & 1)));
                }
            }
            GPE_PUTSCOM(GPE_SCOM_ADDR_QUAD(QPPM_QPMMR_CLR, q), BIT64(22) | BIT64(24) | BIT64(26));
            if(cme_flags & BIT64(CME_FLAGS_RCLK_OPERABLE))
            {
                GPE_GETSCOM(GPE_SCOM_ADDR_QUAD(QPPM_QACCR, q), value);
                baseVal = value & BITS64(13, 51);
                value &= BITS64(0, 15);
                value = value >> 48;
                idx_off = G_gppb->resclk.resclk_index[0];
                idx = idx_off;
                while(idx < RESCLK_STEPS)
                {
                    if (G_gppb->resclk.steparray[idx].value == value)
                    {
                        break;
                    }
                    else
                    {
                        idx++;
                    }
                }
                if (idx == RESCLK_STEPS)
                {
                    PK_TRACE_DBG("CER:Resclk Idx Search Failed");
                    PGPE_TRACE_AND_PANIC(PGPE_RESCLK_IDX_SEARCH_FAIL);
                }
                while (idx > idx_off)
                {
                    value = (((uint64_t)G_gppb->resclk.steparray[--idx].value) << 48) | baseVal;
                    GPE_PUTSCOM(GPE_SCOM_ADDR_QUAD(QPPM_QACCR, q), value);
                }
            }
            dpllFreq.value = 0;
            dpllFreq.fields.fmax  = G_gppb->dpll_pstate0_value - G_pgpe_pstate_record.safePstate;
            dpllFreq.fields.fmult = dpllFreq.fields.fmax;
            dpllFreq.fields.fmin  = dpllFreq.fields.fmax;
            GPE_PUTSCOM(GPE_SCOM_ADDR_QUAD(QPPM_DPLL_FREQ, q), dpllFreq.value);
            freq_done = 0;
            do
            {
                Read DPLL_STAT
                GPE_GETSCOM(GPE_SCOM_ADDR_QUAD(QPPM_DPLL_STAT, q), value);
                if(cme_flags & BIT64(CME_FLAGS_VDM_OPERABLE))
                {
                    freq_done = value & BIT64(60); [UPDATE_COMPLETE]=1 means done
                }
                else
                {
                    freq_done = !(value & BIT64(61)); [FREQ_CHANGE]=0 means done
                }
            }
            while (!freq_done);
            2. The quad in error is removed from the expected Ack vector.
            G_pgpe_pstate_record.activeQuads &= (~QUAD_MASK(q));
            G_pgpe_pstate_record.activeDB &= ~(QUAD_ALL_CORES_MASK(q));
            PK_TRACE_DBG("CER: Quad[%d] ResclkDisabled, Moved to Fsafe, and removed from activeQuads", q);
        }
    }
    PK_TRACE_INF("CER: CME Fault Processed");
    if (!(in32(G_OCB_OCCFLG) & BIT32(PGPE_PROLONGED_DROOP_WORKAROUND_ACTIVE)))
    {
        p9_pgpe_pstate_write_core_throttle(CORE_THROTTLE_OFF, RETRY);
    }
    It is safe for PGPE to leave VDMs enabled and not change the vid compare
    or thresholds later when the external voltage is dropped to Psafe worst
    case, VDMs on the failing Quad will indicate a permanent droop which
    causes the DPLL to drop 12.5% even if not needed
    if((G_pgpe_pstate_record.pstatesStatus == PSTATE_ACTIVE))
    {
        G_pgpe_pstate_record.pstatesStatus = PSTATE_SAFE_MODE_PENDING;
    }
    else
    {
        Ack any pending IPCs from OCC and SGPE
        p9_pgpe_pstate_handle_pending_occ_ack_on_fault();
        p9_pgpe_pstate_handle_pending_sgpe_ack_on_fault();
        p9_pgpe_pstate_cme_fault();
    }
    G_pgpe_pstate_record.severeFault[SAFE_MODE_FAULT_CME] = 1;
}
void p9_pgpe_irq_handler_cme_err ( ) { uint32_t c , q , idx , idx_off , freq_done ; uint32_t opit5pr ; uint32_t opit5prQuad ; uint64_t value , baseVal , coreSsh ; qppm_dpll_freq_t dpllFreq ; ocb_qcsr_t qcsr ; qcsr . value = in32 ( G_OCB_QCSR ) ; uint64_t cme_flags = 0 ; G_pgpe_optrace_data . word [ 0 ] = ( G_pgpe_pstate_record . activeQuads << 24 ) | ( G_pgpe_pstate_record . activeCores << 8 ) ; G_pgpe_optrace_data . word [ 1 ] = ( G_pgpe_pstate_record . psCurr . fields . glb << 24 ) | ( G_pgpe_pstate_record . extVrmCurr << 8 ) | PGPE_OP_TRACE_CME_FAULT ; p9_pgpe_optrace ( SEVERE_FAULT_DETECTED ) ; PGPE_OPTIONAL_TRACE_AND_PANIC ( PGPE_CME_FAULT ) ; opit5pr = in32 ( OCB_OPIT5PRA ) ; out32 ( OCB_OPIT5PRA_CLR , opit5pr ) ; PK_TRACE_INF ( " " , opit5pr ) ; if ( ! ( in32 ( G_OCB_OCCFLG ) & BIT32 ( PGPE_PROLONGED_DROOP_WORKAROUND_ACTIVE ) ) ) { p9_pgpe_pstate_write_core_throttle ( CORE_IFU_THROTTLE , RETRY ) ; } for ( q = 0 ; q < MAX_QUADS ; q ++ ) { opit5prQuad = ( opit5pr >> ( ( MAX_QUADS - q + 1 ) << 2 ) ) & 0xf ; if ( opit5prQuad ) { G_pgpe_pstate_record . errorQuads |= QUAD_MASK ( q ) ; PK_TRACE_INF ( " " , q ) ; if ( qcsr . fields . ex_config & QUAD_EX0_MASK ( q ) ) { GPE_PUTSCOM ( GPE_SCOM_ADDR_CME ( CME_SCOM_XIXCR , q , 0 ) , BIT64 ( 3 ) ) ; GPE_GETSCOM ( GPE_SCOM_ADDR_CME ( CME_SCOM_FLAGS , q , 0 ) , cme_flags ) ; } if ( qcsr . fields . ex_config & QUAD_EX1_MASK ( q ) ) { GPE_PUTSCOM ( GPE_SCOM_ADDR_CME ( CME_SCOM_XIXCR , q , 1 ) , BIT64 ( 3 ) ) ; if ( ! ( qcsr . fields . ex_config & QUAD_EX0_MASK ( q ) ) ) { GPE_GETSCOM ( GPE_SCOM_ADDR_CME ( CME_SCOM_FLAGS , q , 1 ) , cme_flags ) ; } } for ( c = 0 ; c < CORES_PER_QUAD ; c ++ ) { GPE_GETSCOM_VAR ( PPM_SSHSRC , CORE_ADDR_BASE , ( ( q << 2 ) + c ) , 0 , coreSsh ) ; if ( ! ( coreSsh & BIT64 ( 0 ) ) ) { GPE_PUTSCOM ( GPE_SCOM_ADDR_CME ( CME_SCOM_LMCR_CLR , q , ( ( c & 2 ) >> 1 ) ) , ( BIT64 ( 12 ) >> ( c & 1 ) ) ) ; } } GPE_PUTSCOM ( GPE_SCOM_ADDR_QUAD ( QPPM_QPMMR_CLR , q ) , BIT64 ( 22 ) | BIT64 ( 24 ) | BIT64 ( 26 ) ) ; if ( cme_flags & BIT64 ( CME_FLAGS_RCLK_OPERABLE ) ) { GPE_GETSCOM ( GPE_SCOM_ADDR_QUAD ( QPPM_QACCR , q ) , value ) ; baseVal = value & BITS64 ( 13 , 51 ) ; value &= BITS64 ( 0 , 15 ) ; value = value >> 48 ; idx_off = G_gppb -> resclk . resclk_index [ 0 ] ; idx = idx_off ; while ( idx < RESCLK_STEPS ) { if ( G_gppb -> resclk . steparray [ idx ] . value == value ) { break ; } else { idx ++ ; } } if ( idx == RESCLK_STEPS ) { PK_TRACE_DBG ( " " ) ; PGPE_TRACE_AND_PANIC ( PGPE_RESCLK_IDX_SEARCH_FAIL ) ; } while ( idx > idx_off ) { value = ( ( ( uint64_t ) G_gppb -> resclk . steparray [ -- idx ] . value ) << 48 ) | baseVal ; GPE_PUTSCOM ( GPE_SCOM_ADDR_QUAD ( QPPM_QACCR , q ) , value ) ; } } dpllFreq . value = 0 ; dpllFreq . fields . fmax = G_gppb -> dpll_pstate0_value - G_pgpe_pstate_record . safePstate ; dpllFreq . fields . fmult = dpllFreq . fields . fmax ; dpllFreq . fields . fmin = dpllFreq . fields . fmax ; GPE_PUTSCOM ( GPE_SCOM_ADDR_QUAD ( QPPM_DPLL_FREQ , q ) , dpllFreq . value ) ; freq_done = 0 ; do { GPE_GETSCOM ( GPE_SCOM_ADDR_QUAD ( QPPM_DPLL_STAT , q ) , value ) ; if ( cme_flags & BIT64 ( CME_FLAGS_VDM_OPERABLE ) ) { freq_done = value & BIT64 ( 60 ) ; } else { freq_done = ! ( value & BIT64 ( 61 ) ) ; } } while ( ! freq_done ) ; G_pgpe_pstate_record . activeQuads &= ( ~ QUAD_MASK ( q ) ) ; G_pgpe_pstate_record . activeDB &= ~ ( QUAD_ALL_CORES_MASK ( q ) ) ; PK_TRACE_DBG ( " " , q ) ; } } PK_TRACE_INF ( " " ) ; if ( ! ( in32 ( G_OCB_OCCFLG ) & BIT32 ( PGPE_PROLONGED_DROOP_WORKAROUND_ACTIVE ) ) ) { p9_pgpe_pstate_write_core_throttle ( CORE_THROTTLE_OFF , RETRY ) ; } if ( ( G_pgpe_pstate_record . pstatesStatus == PSTATE_ACTIVE ) ) { G_pgpe_pstate_record . pstatesStatus = PSTATE_SAFE_MODE_PENDING ; } else { p9_pgpe_pstate_handle_pending_occ_ack_on_fault ( ) ; p9_pgpe_pstate_handle_pending_sgpe_ack_on_fault ( ) ; p9_pgpe_pstate_cme_fault ( ) ; } G_pgpe_pstate_record . severeFault [ SAFE_MODE_FAULT_CME ] = 1 ; }
p9_pgpe_irq_handler_cme_err
Handles CME error interrupt which is pcb type5 interrupt
p9_pgpe_irq_handler_cme_err Handles CME error interrupt which is pcb type5 interrupt
//Optrace //Halt if DEBUG_HALT is set //Check which CMEs sent Type5 //If prolonged droop recovery is not active //1.1 Halt both CMEs in the quad containing faulted CME, //XCR[1:3] = 001(Halt the CME) //XCR[1:3] = 001(Halt the CME) //Read CME1 CME_FLAGS, if CME0 not configured /// Also read stop history of the cores belongs to both cmes, //  and assert auto special wakeup mode for the core that is not gated. //1.2 The quad in error is stepped out of resonance by the PGPE. This keeps the cores that may be //  running in the quad operating. There is a momentary rise in power as resonance is disabled. //  (~100us). //Open Analog Controls for SCOM access in this quad //. Read the QACCR //Search from the lowest index of the resclk table until a match to the QACCR value //PGPE steps down from that index to the off index value //1.3 Move DPLL to Fsafe (~100us) // poll DPLL Status frequency change done before proceeding // //Read DPLL_STAT //[UPDATE_COMPLETE]=1 means done //[FREQ_CHANGE]=0 means done //2. The quad in error is removed from the expected Ack vector. //If prolonged droop recovery is not active //It is safe for PGPE to leave VDMs enabled and not change the vid compare //or thresholds later when the external voltage is dropped to Psafe worst //case, VDMs on the failing Quad will indicate a permanent droop which //causes the DPLL to drop 12.5% even if not needed //Ack any pending IPCs from OCC and SGPE