From 360934dea9355e488206267d7f9fd9b1c753cf16 Mon Sep 17 00:00:00 2001 From: Wael El-Essawy Date: Fri, 9 Dec 2016 18:28:26 -0600 Subject: [PATCH] Pstates Support in OCC 1. Initialize Pstates global parameters (G_proc_fmax, G_proc_fmin, G_khz_per_pstate and G_proc_pmin from the OCC Pstate Parameter Block) 2. When frequency config data packet is received and OCC is NOT already in Active state: Send IPC command to PGPE to set pState clips to be wide open from min frequency to turbo First verify min/max frequency from TMGT is within what PGPE allows saved in G_proc_fmax and G_proc_fmin if not within bounds trace and clip to G_proc_fmax/fmin) 3. Transition to active state: Send IPC command to PGPE to start pState protocol (give correct data for OCC vs OPAL in control of Pstates) and if OPAL system update OPAL shared memory with Pstate information. 4. amec_slv_freq_smh(): Send IPC command to PGPE to set requested pState (PowerVM) or set clips (OPAL). 5. Address all the TODO/TEMP/#if 0 in amec_freq.c either remove or add RTC# for when it will be addressed Change-Id: Ic323321b8c66945732a6b7345ad85d6f41a62edd RTC: 130201 Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/33704 Tested-by: FSP CI Jenkins Reviewed-by: Martha Broyles Reviewed-by: Andres A. Lugo-Reyes Reviewed-by: Wael El-Essawy --- src/common/ipc_func_ids.h | 12 +- src/include/p9_pstates_occ.h | 2 + src/occ_405/Makefile | 3 +- src/occ_405/amec/amec_data.c | 37 +- src/occ_405/amec/amec_freq.c | 76 +- src/occ_405/amec/amec_sys.h | 2 - src/occ_405/cmdh/cmdh_fsp_cmds_datacnfg.c | 73 +- src/occ_405/homer.h | 4 + src/occ_405/img_defs.mk | 1 + src/occ_405/incl/comp_ids.h | 5 + src/occ_405/incl/occ_common.h | 3 +- src/occ_405/main.c | 356 +++++++++- src/occ_405/occLinkInputFile | 2 + src/occ_405/occ_service_codes.h | 19 +- src/occ_405/occ_sys_config.h | 1 + src/occ_405/pgpe/pgpe_interface.c | 812 ++++++++++++++++++++++ src/occ_405/pgpe/pgpe_interface.h | 45 ++ src/occ_405/pgpe/pgpe_service_codes.h | 46 ++ src/occ_405/{ => pgpe}/pgpe_shared.h | 33 +- src/occ_405/proc/proc_data.c | 9 +- src/occ_405/proc/proc_data_control.c | 287 +++----- src/occ_405/proc/proc_data_control.h | 27 +- src/occ_405/proc/proc_pstate.c | 245 +++---- src/occ_405/proc/proc_pstate.h | 37 +- src/occ_405/pss/apss.c | 2 +- src/occ_405/rtls/rtls.h | 8 +- src/occ_405/rtls/rtls_service_codes.h | 13 +- src/occ_405/rtls/rtls_tables.c | 35 +- src/occ_405/state.c | 106 ++- src/occ_405/timer/timer.c | 8 +- src/occ_405/topfiles.mk | 2 + 31 files changed, 1843 insertions(+), 468 deletions(-) create mode 100644 src/occ_405/pgpe/pgpe_interface.c create mode 100644 src/occ_405/pgpe/pgpe_interface.h create mode 100644 src/occ_405/pgpe/pgpe_service_codes.h rename src/occ_405/{ => pgpe}/pgpe_shared.h (70%) diff --git a/src/common/ipc_func_ids.h b/src/common/ipc_func_ids.h index 72193b58..da2285e2 100644 --- a/src/common/ipc_func_ids.h +++ b/src/common/ipc_func_ids.h @@ -73,12 +73,12 @@ IPC_FUNCIDS_TABLE_START //Functions that are only supported by GPE2 should be defined here //These function ID's can only be sent to GPE2 (PGPE) IPC_FUNCIDS_ST_START(OCCHW_INST_ID_GPE2) - IPC_FUNC_ID(IPC_PGPE_INVALID_FUNCID) - IPC_FUNC_ID(IPC_PGPE_START_SUSPEND_FUNCID) - IPC_FUNC_ID(IPC_PGPE_CLIPS_FUNCID) - IPC_FUNC_ID(IPC_PGPE_SET_PMCR_FUNCID) - IPC_FUNC_ID(IPC_PGPE_WOF_CONTROL_FUNCID) - IPC_FUNC_ID(IPC_PGPE_WOF_VFRT_FUNCID) + IPC_FUNC_ID(IPC_MSGID_405_INVALID) + IPC_FUNC_ID(IPC_MSGID_405_START_SUSPEND) + IPC_FUNC_ID(IPC_MSGID_405_CLIPS) + IPC_FUNC_ID(IPC_MSGID_405_SET_PMCR) + IPC_FUNC_ID(IPC_MSGID_405_WOF_CONTROL) + IPC_FUNC_ID(IPC_MSGID_405_WOF_VFRT) IPC_FUNCIDS_ST_END(OCCHW_INST_ID_GPE2) //Functions that are only supported by GPE3 should be defined here diff --git a/src/include/p9_pstates_occ.h b/src/include/p9_pstates_occ.h index d3fa62b6..e69e5008 100644 --- a/src/include/p9_pstates_occ.h +++ b/src/include/p9_pstates_occ.h @@ -168,6 +168,8 @@ typedef struct // Minimum Pstate; Maximum is always 0. uint32_t pstate_min; // Comes from PowerSave #V point after biases + // TODO: Temporary hack untill interface is finalized. + uint8_t pad[88]; // total size = 0xE00, devisible by 128 } OCCPstateParmBlock; diff --git a/src/occ_405/Makefile b/src/occ_405/Makefile index 3fb12501..f64a3196 100755 --- a/src/occ_405/Makefile +++ b/src/occ_405/Makefile @@ -69,7 +69,8 @@ LIB_DIRS = -L$(OBJDIR) \ -L$(OBJDIR)/firdata \ -L$(OBJDIR)/cent \ -L$(OBJDIR)/mem \ - -L$(OBJDIR)/wof + -L$(OBJDIR)/wof \ + -L$(OBJDIR)/pgpe #default target is to make a binary application image .PHONY : all diff --git a/src/occ_405/amec/amec_data.c b/src/occ_405/amec/amec_data.c index 6663cdc9..05d60b95 100755 --- a/src/occ_405/amec/amec_data.c +++ b/src/occ_405/amec/amec_data.c @@ -47,6 +47,8 @@ #include #include #include +#include +#include //************************************************************************* // Externs @@ -64,8 +66,9 @@ // Globals //************************************************************************* extern uint8_t G_occ_interrupt_type; -extern uint32_t G_proc_fmin; -extern uint32_t G_proc_fmax; + +//max(fturbo,futurbo) +extern uint16_t G_proc_fmax_mhz; //************************************************************************* // Function Prototypes @@ -98,16 +101,13 @@ errlHndl_t AMEC_data_write_fcurr(const OCC_MODE i_mode) /* Code */ /*------------------------------------------------------------------------*/ - // If we're active we need to load this new range into DVFS MIN/MAX - if(CURRENT_STATE() == OCC_STATE_ACTIVE) - { - // Use i_mode here since this function understands turbo - l_err = amec_set_freq_range(i_mode); + // Load new range into DVFS MIN/MAX, + // Use i_mode here since this function understands turbo + l_err = amec_set_freq_range(i_mode); - if(l_err) - { - //break; - } + if(l_err) + { + //break; } // If we are in OpenPower environment with OPAL, load this new range into DVFS @@ -115,14 +115,25 @@ errlHndl_t AMEC_data_write_fcurr(const OCC_MODE i_mode) // in amec_set_freq_range() based on mode if((G_occ_interrupt_type != FSP_SUPPORTED_OCC) && (G_sysConfigData.system_type.kvm)) { - g_amec->sys.fmax = G_proc_fmax; - g_amec->sys.fmin = G_proc_fmin; // = G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY] + g_amec->sys.fmax = G_proc_fmax_mhz; + g_amec->sys.fmin = G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY]; TRAC_INFO("AMEC_data_write_fcurr: New frequency range Fmin[%u] Fmax[%u]", g_amec->sys.fmin, g_amec->sys.fmax); } + if(!l_err) + { + // set the clip bounds wide open (if not in active state) + // if not already in active mode, send IPC command to PGPE to set + // pStates clips wide open (pmin - pmax) + if(!IS_OCC_STATE_ACTIVE()) + { + l_err = pgpe_widen_clip_ranges(); + } + } + return l_err; } diff --git a/src/occ_405/amec/amec_freq.c b/src/occ_405/amec/amec_freq.c index 7115b376..5dadfa71 100755 --- a/src/occ_405/amec/amec_freq.c +++ b/src/occ_405/amec/amec_freq.c @@ -56,6 +56,11 @@ extern uint8_t G_cent_temp_expired_bitmap; extern dimm_sensor_flags_t G_dimm_temp_expired_bitmap; +extern uint16_t G_proc_fmax_mhz; + +extern GPE_BUFFER(PstatesClips* G_core_data_control_occwrite_ptr); + + //************************************************************************* // Defines/Enums //************************************************************************* @@ -67,12 +72,12 @@ extern dimm_sensor_flags_t G_dimm_temp_expired_bitmap; //************************************************************************* // Globals //************************************************************************* -BOOLEAN G_non_dps_power_limited = FALSE; +BOOLEAN G_non_dps_power_limited = FALSE; opal_proc_voting_reason_t G_amec_opal_proc_throt_reason = NO_THROTTLE; opal_mem_voting_reason_t G_amec_opal_mem_throt_reason = NO_MEM_THROTTLE; -uint16_t G_time_until_freq_check = FREQ_CHG_CHECK_TIME; +uint16_t G_time_until_freq_check = FREQ_CHG_CHECK_TIME; //FFDC SCOM addresses as requested by Greg Still in defect SW247927 //If new SCOM addresses are added, update the size of the array. @@ -162,7 +167,15 @@ errlHndl_t amec_set_freq_range(const OCC_MODE i_mode) /*------------------------------------------------------------------------*/ // First set to Max Freq Range for this mode - if( VALID_MODE(i_mode) ) + // if no mode set yet default to the full range + if(i_mode == OCC_MODE_NOCHANGE) + { + l_freq_min = G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY]; + + // Set Max frequency (ultra turbo freq if wof enabled, to turbo freq otherwise) + l_freq_max = G_proc_fmax_mhz; + } + else if( VALID_MODE(i_mode) ) // Set to Max Freq Range for this mode { l_freq_min = G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY]; l_freq_max = G_sysConfigData.sys_mode_freq.table[i_mode]; @@ -573,39 +586,54 @@ void amec_slv_proc_voting_box(void) // End Function Specification void amec_slv_freq_smh(void) { -// RTC:130201 -// TODO/TEMP: Remove '#if 0' when/if needed. Currently does nothing and -// causes warning of set but not used.. -#if 0 - /*------------------------------------------------------------------------*/ /* Local Variables */ /*------------------------------------------------------------------------*/ - uint16_t k = 0; - Pstate l_pstate[MAX_NUM_CORES]; + 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 = 0; // select the maximum pstate (minimum frequency) + // within each quad, initialize to 0 /*------------------------------------------------------------------------*/ /* Code */ /*------------------------------------------------------------------------*/ - for (k=0; kproc[0].core[k].f_request); - } + for (core_idx=0; core_idxproc[0].core[core_num].f_request)) + { + pmax = proc_freq2pstate(g_amec->proc[0].core[core_num].f_request); + } + } - if(G_sysConfigData.system_type.kvm) - { - // Send IPC with G_proc_pmin and l_pstate to set pmin and pmax clips - } - else - { - // send an IPC with l_pstate to set pstates for all Cores + // set quad clip bounds/pstates based on system type + if(G_sysConfigData.system_type.kvm) + { + // update quad bounds on OPAL systems + G_core_data_control_occwrite_ptr->clips.ps_val_clip_min[quad] = + G_opal_static_table.config.pmin; + G_core_data_control_occwrite_ptr->clips.ps_val_clip_max[quad] = pmax; + + PROC_DBG("Setting Quad %d's min-max clip bounds to %d-%d\n", + quad, G_opal_static_table.config.pmin, pmax); + } + else + { + // update quad pstate request on non-OPAL systems + G_core_data_control_occwrite_ptr->pstates.pmcr[quad] = + ((uint64_t) pmax << 48) +1; // Version 1 (Power9 format) + + PROC_DBG("Setting Quad %d's Pstate to %d\n",quad, pmax); + } + + pmax = 0; // initialize for next loop iteration } -#endif } diff --git a/src/occ_405/amec/amec_sys.h b/src/occ_405/amec/amec_sys.h index d298c7f0..bf2a0036 100755 --- a/src/occ_405/amec/amec_sys.h +++ b/src/occ_405/amec/amec_sys.h @@ -337,8 +337,6 @@ typedef struct uint16_t f_request; // Reason for the frequency request generated by the voting box uint32_t f_reason; - // Current state of this core frequency state machine - uint8_t f_sms; } amec_core_t; diff --git a/src/occ_405/cmdh/cmdh_fsp_cmds_datacnfg.c b/src/occ_405/cmdh/cmdh_fsp_cmds_datacnfg.c index d3e9a3f8..30e2ea98 100755 --- a/src/occ_405/cmdh/cmdh_fsp_cmds_datacnfg.c +++ b/src/occ_405/cmdh/cmdh_fsp_cmds_datacnfg.c @@ -42,6 +42,7 @@ #include #include "dimm.h" #include +#include "p9_pstates_occ.h" #define FREQ_FORMAT_PWR_MODE_NUM 6 #define FREQ_FORMAT_BASE_DATA_SZ (sizeof(cmdh_store_mode_freqs_t) - sizeof(cmdh_fsp_cmd_header_t)) @@ -67,12 +68,8 @@ extern uint8_t G_occ_interrupt_type; -extern uint32_t G_proc_fmin; -extern uint32_t G_proc_fmax; -extern uint32_t G_khz_per_pstate; - -extern uint8_t G_proc_pmin; -extern uint8_t G_proc_pmax; +extern uint16_t G_proc_fmax_mhz; // Maximum frequency (uturbo if WOF enabled, otherwise turbo) +extern OCCPstateParmBlock G_oppb; // OCC Pstate Parameters Block Structure typedef struct data_req_table { @@ -284,39 +281,64 @@ errlHndl_t data_store_freq_data(const cmdh_fsp_cmd_t * i_cmd_ptr, // Bytes 3-4 Nominal Frequency Point l_freq = (l_buf[0] << 8 | l_buf[1]); l_table[OCC_MODE_NOMINAL] = l_freq; - CMDH_TRAC_INFO("Nominal frequency = %d", l_freq); + CMDH_TRAC_INFO("Nominal frequency = %d MHz", l_freq); // Bytes 5-6 Turbo Frequency Point: // also store for DPS modes l_freq = (l_buf[2] << 8 | l_buf[3]); + // Verify that turbo frequency is <= G_proc_fmax_mhz + if(l_freq > G_proc_fmax_mhz) + { + CMDH_TRAC_ERR("Turbo Frequency[%d] (MHz)) is higher than " + "G_proc_fmax_mhz[%d], clip Turbo Frequency", + l_freq, G_proc_fmax_mhz); + l_freq = G_proc_fmax_mhz; + } l_table[OCC_MODE_TURBO] = l_freq; l_table[OCC_MODE_DYN_POWER_SAVE] = l_freq; l_table[OCC_MODE_DYN_POWER_SAVE_FP] = l_freq; - CMDH_TRAC_INFO("Turbo frequency = %d", l_freq); + CMDH_TRAC_INFO("Turbo frequency = %d MHz", l_freq); // Bytes 7-8 Minimum Frequency Point l_freq = (l_buf[4] << 8 | l_buf[5]); + // Verify that minimum frequency is >= G_oppb.frequency_min_khz + if(l_freq * 1000 < G_oppb.frequency_min_khz) + { + CMDH_TRAC_ERR("Minimum Frequency[%d] (Mhz) is lower than PGPE's " + "G_oppb.frequency_min_khz[%d], clip Minimum Frequency", + l_freq, G_oppb.frequency_min_khz); + l_freq = G_oppb.frequency_min_khz / 1000; + } l_table[OCC_MODE_MIN_FREQUENCY] = l_freq; - G_proc_fmin = l_freq; - CMDH_TRAC_INFO("Minimum frequency = %d", l_freq); + CMDH_TRAC_INFO("Minimum frequency = %d MHz", l_freq); // Bytes 9-10 Ultr Turbo Frequency Point l_freq = (l_buf[6] << 8 | l_buf[7]); - if(l_freq) + // Verify that ultra turbo frequency is <= G_proc_fmax_mhz + if(l_freq > G_proc_fmax_mhz) + { + CMDH_TRAC_ERR("Ultra Turbo Frequency[%d] (MHz) is higher than PGPE's " + "Max freq (G_proc_fmax_mhz[%d]) clip Ultra Turbo Frequency", + l_freq, G_proc_fmax_mhz); + l_freq = G_proc_fmax_mhz; + } + l_table[OCC_MODE_UTURBO] = l_freq; + CMDH_TRAC_INFO("UT frequency = %d MHz", l_freq); + + // clip G_proc_fmax_mhz to TMGT's MAX(turbo, ultra turbo) frequency point + if(l_table[OCC_MODE_UTURBO] > l_table[OCC_MODE_TURBO]) { - G_proc_fmax = l_freq; + G_proc_fmax_mhz = l_table[OCC_MODE_UTURBO]; } - else // If Ultra Turbo Frequency Point = 0, Fmax = Turbo Frequency + else { - G_proc_fmax = l_table[OCC_MODE_TURBO]; + G_proc_fmax_mhz = l_table[OCC_MODE_TURBO]; } - l_table[OCC_MODE_UTURBO] = l_freq; - CMDH_TRAC_INFO("UT frequency = %d", l_freq); // Bytes 11-12 Static Power Save Frequency Point l_freq = (l_buf[8] << 8 | l_buf[9]); l_table[OCC_MODE_PWRSAVE] = l_freq; - CMDH_TRAC_INFO("Static Power Save frequency = %d", l_freq); + CMDH_TRAC_INFO("Static Power Save frequency = %d MHz", l_freq); // Bytes 13-14 FFO Frequency Point l_freq = (l_buf[10] << 8 | l_buf[11]); @@ -324,19 +346,19 @@ errlHndl_t data_store_freq_data(const cmdh_fsp_cmd_t * i_cmd_ptr, { // Check and make sure that FFO freq is within valid range const uint16_t l_req_freq = l_freq; - if (l_freq < G_proc_fmin) + if (l_freq < l_table[OCC_MODE_MIN_FREQUENCY]) { - l_freq = G_proc_fmin; + l_freq = l_table[OCC_MODE_MIN_FREQUENCY]; } - else if (l_freq > G_proc_fmax) + else if (l_freq > G_proc_fmax_mhz) { - l_freq = G_proc_fmax; + l_freq = G_proc_fmax_mhz; } // Log an error if we could not honor the requested FFO frequency, but keep going. if (l_req_freq != l_freq) { - TRAC_ERR("FFO Frequency out of range. requested %d, but using %d", + TRAC_ERR("FFO Frequency out of range. requested %d MHz, but using %d MHz", l_req_freq, l_freq); /* @ * @errortype @@ -360,10 +382,7 @@ errlHndl_t data_store_freq_data(const cmdh_fsp_cmd_t * i_cmd_ptr, } } l_table[OCC_MODE_FFO] = l_freq; - CMDH_TRAC_INFO("FFO Frequency = %d", l_freq); - - // Calculate minimum Pstate: - G_proc_pmin = G_proc_pmax + ((G_proc_fmax - G_proc_fmin)/G_khz_per_pstate); + CMDH_TRAC_INFO("FFO Frequency = %d Mhz", l_freq); // inconsistent Frequency Points? if((l_table[OCC_MODE_UTURBO] < l_table[OCC_MODE_TURBO] && l_table[OCC_MODE_UTURBO]) || @@ -2091,6 +2110,8 @@ errlHndl_t DATA_store_cnfgdata (const cmdh_fsp_cmd_t * i_cmd_ptr, l_errlHndl = data_store_freq_data(i_cmd_ptr , o_rsp_ptr); if(NULL == l_errlHndl) { + // New Frequency config data packet received with no error logs: set the + // DATA_MASK_FREQ_PRESENT to flag that we received the frequency from TMGT l_new_data = DATA_MASK_FREQ_PRESENT; } break; diff --git a/src/occ_405/homer.h b/src/occ_405/homer.h index f276c678..b6347018 100755 --- a/src/occ_405/homer.h +++ b/src/occ_405/homer.h @@ -54,6 +54,10 @@ #define OCC_HTMGT_RSP_OFFSET_HOMER 0x000E1000 #define OCC_HTMGT_RSP_ADDRESS_HOMER (HOMER_BASE_ADDRESS+OCC_HTMGT_RSP_OFFSET_HOMER) +// PPMR Header space +#define PPMR_OFFSET_HOMER 0x00300000 // PPMR image HOMER offset +#define PPMR_ADDRESS_HOMER (HOMER_BASE_ADDRESS+PPMR_OFFSET_HOMER) // PPMR image memory address + // Version(s) of HOMER host data currently supported typedef enum homer_version diff --git a/src/occ_405/img_defs.mk b/src/occ_405/img_defs.mk index abdef459..9dea1ebe 100644 --- a/src/occ_405/img_defs.mk +++ b/src/occ_405/img_defs.mk @@ -240,6 +240,7 @@ APP_INCLUDES = -I$(IMAGE_SRCDIR)/rtls \ -I$(IMAGE_SRCDIR)/lock \ -I$(IMAGE_SRCDIR)/wof \ -I$(IMAGE_SRCDIR)/../common \ + -I$(IMAGE_SRCDIR)/pgpe \ INCLUDES += $(IMG_INCLUDES) $(GLOBAL_INCLUDES) $(APP_INCLUDES) \ -I$(SSX_SRCDIR)/ssx -I$(SSX_SRCDIR)/ppc32 -I$(SSX_SRCDIR)/ppc405 \ diff --git a/src/occ_405/incl/comp_ids.h b/src/occ_405/incl/comp_ids.h index 893b9f9c..e6270d6b 100755 --- a/src/occ_405/incl/comp_ids.h +++ b/src/occ_405/incl/comp_ids.h @@ -91,5 +91,10 @@ // Workload Optimize Frequency #define WOF_COMP_ID 0x1100 #define WOF_COMP_NAME "WOF" + +// PGPE Interface +#define PGPE_COMP_ID 0x1200 +#define PGPE_COMP_NAME "PGPE" + #endif diff --git a/src/occ_405/incl/occ_common.h b/src/occ_405/incl/occ_common.h index 2dc0c9fe..eadcd95b 100755 --- a/src/occ_405/incl/occ_common.h +++ b/src/occ_405/incl/occ_common.h @@ -261,7 +261,8 @@ enum NEST_DTS_INITIALIZED = 0x0700, CENTAUR_INITIALIZED = 0x07ff, SLAVE_OCC_INITIALIZED = 0x08ff, - PGPE_IMAGE_HEADER_READ = 0x098f, + PGPE_IMAGE_HEADER_READ = 0x094f, + PPMR_IMAGE_HEADER_READ = 0x098f, WATCHDOG_INITIALIZED = 0x09ff, RTL_TIMER_INITIALIZED = 0x0aff, SEMS_AND_TIMERS_INITIALIZED = 0x0bff, diff --git a/src/occ_405/main.c b/src/occ_405/main.c index fdbe9f36..e4eaf6e8 100755 --- a/src/occ_405/main.c +++ b/src/occ_405/main.c @@ -59,6 +59,7 @@ #include "occhw_shared_data.h" #include #include +#include extern uint32_t __ssx_boot; // Function address is 32 bits extern uint32_t G_occ_phantom_critical_count; @@ -78,8 +79,13 @@ extern uint32_t G_pgpe_beacon_address; IMAGE_HEADER (G_mainAppImageHdr,__ssx_boot,MAIN_APP_ID,ID_NUM_INVALID); // PGPE Image Header Parameters -uint32_t G_pgpe_sram_address; -uint32_t G_pgpe_sram_sz; +uint32_t G_pgpe_shared_sram_address = 0; +uint32_t G_pgpe_shared_sram_sz = 0; + +ppmr_header_t G_ppmr_header; // PPMR Header layout format +OCCPstateParmBlock G_oppb; // OCC Pstate Parameters Block Structure +extern uint16_t G_proc_fmax_mhz; // max(turbo,uturbo) frequencies + //Set main thread timer for one second #define MAIN_THRD_TIMER_SLICE ((SsxInterval) SSX_SECONDS(1)) @@ -119,6 +125,7 @@ extern uint8_t g_trac_err_buffer[]; void pmc_hw_error_isr(void *private, SsxIrqId irq, int priority); void create_tlb_entry(uint32_t address, uint32_t size); +void read_oppb_params(const OCCPstateParmBlock* occ_ppb); //Macro creates a 'bridge' handler that converts the initial fast-mode to full //mode interrupt handler @@ -404,8 +411,9 @@ void create_tlb_entry(uint32_t address, uint32_t size) tlb_entry_size = PAGE_ALIGNED_SIZE(size); } + #if PPC405_MMU_SUPPORT - // define DTLB for PGPE image header + // define DTLB for page aligned address and size l_rc = ppc405_mmu_map( tlb_entry_address, tlb_entry_address, @@ -465,33 +473,308 @@ void create_tlb_entry(uint32_t address, uint32_t size) void read_pgpe_header(void) { + uint64_t magic_number; + errlHndl_t l_err; // define DTLB for the PGPE image header create_tlb_entry(PGPE_HEADER_ADDR, PGPE_HEADER_SZ); - // Read PGPE Beacon address from PGPE image header - G_pgpe_beacon_address = in32(PGPE_BEACON_ADDR_PTR); + // verify the validity of the magic number + magic_number = in64(PGPE_HEADER_ADDR); + if(PGPE_MAGIC_NUMBER != magic_number) + { + // The Magic number is invalid .. Invalid or corrupt PGPE image header + MAIN_TRAC_ERR("Invalid PGPGE Magic number. Address[0x%08X], Magic Number[0x%08X%08X]", + PGPE_HEADER_ADDR, (uint32_t)(magic_number>>32), (uint32_t)magic_number); + /* @ + * @errortype + * @moduleid READ_PGPE_HEADER + * @reasoncode INVALID_MAGIC_NUMBER + * @userdata1 Low order 32 bits of retrieved PGPE magic number + * @userdata2 Hight order 32 bits of retrieved PGPE magic number + * @userdata4 OCC_NO_EXTENDED_RC + * @devdesc SSX semaphore related failure + */ - MAIN_TRAC_IMP("Read PGPE Beacon Address[0x%08x]", - G_pgpe_beacon_address); + l_err = createErrl(READ_PGPE_HEADER, //modId + INVALID_MAGIC_NUMBER, //reasoncode + OCC_NO_EXTENDED_RC, //Extended reason code + ERRL_SEV_UNRECOVERABLE, //Severity + NULL, //Trace Buf + DEFAULT_TRACE_SIZE, //Trace Size + (uint32_t)magic_number, //userdata1 + (uint32_t)(magic_number>>32)); //userdata2 - // Read OCC/PGPE Shared SRAM address and size - G_pgpe_sram_address = in32(PGPE_SHARED_SRAM_ADDR_PTR); - G_pgpe_sram_sz = in32(PGPE_SHARED_SRAM_SZ_PTR); + REQUEST_RESET(l_err); - MAIN_TRAC_IMP("Read PGPE Shared SRAM Start Address[0x%08x], Size[0x%08x]", - G_pgpe_sram_address, G_pgpe_sram_sz); + } - // PGPE Beacon is not implemented in simics yet - // the G_pgpe_sram_address and G_pgpe_sram_sz pointers don't - // have the proper values yet. - // @TODO: remove this condition when PGPE code is integrated. RTC: 163934 - if(!G_simics_environment) + if(l_err == NULL) { - // define DTLB for OCC/PGPE shared SRAM, which enables access - // to OCC-PGPE Shared SRAM space, including pgpe_beacon - create_tlb_entry(G_pgpe_sram_address, G_pgpe_sram_sz); + // Read PGPE Beacon address from PGPE image header + G_pgpe_beacon_address = in32(PGPE_BEACON_ADDR_PTR); + + MAIN_TRAC_IMP("Read PGPE Beacon Address[0x%08x]", + G_pgpe_beacon_address); + + // Read OCC/PGPE Shared SRAM address and size + G_pgpe_shared_sram_address = in32(PGPE_SHARED_SRAM_ADDR_PTR); + G_pgpe_shared_sram_sz = in32(PGPE_SHARED_SRAM_SZ_PTR); + + MAIN_TRAC_IMP("Read PGPE Shared SRAM Start Address[0x%08x], Size[0x%08x]", + G_pgpe_shared_sram_address, G_pgpe_shared_sram_sz); + + // PGPE Beacon is not implemented in simics yet + // the G_pgpe_shared_sram_address and G_pgpe_shared_sram_sz pointers don't + // have the proper values yet. + // @TODO: remove this condition when PGPE code is integrated. RTC: 163934 + if(!G_simics_environment) + { + // define DTLB for OCC/PGPE shared SRAM, which enables access + // to OCC-PGPE Shared SRAM space, including pgpe_beacon + create_tlb_entry(G_pgpe_shared_sram_address, G_pgpe_shared_sram_sz); + } } + return; +} + + +/* + * Function Specification + * + * Name: read_ppmr_header + * + * Description: read PPMR image header, and extract the + * OPPB HOMER offset and sturcture size.. + * + * End Function Specification + */ +void read_ppmr_header(void) +{ + int l_ssxrc = SSX_OK; + uint32_t l_reasonCode = 0; + uint32_t l_extReasonCode = 0; + + // error log parameters, if any + uint32_t userdata1 = 0; + uint32_t userdata2 = 0; + + // create a DTLB entry for the PPMR image header + create_tlb_entry(PPMR_ADDRESS_HOMER, sizeof(ppmr_header_t)); + + do{ + // use block copy engine to read the PPMR header + BceRequest pba_copy; + + // Set up a copy request + l_ssxrc = bce_request_create(&pba_copy, // block copy object + &G_pba_bcde_queue, // mainstore to sram copy engine + PPMR_ADDRESS_HOMER, // mainstore address + (uint32_t) &G_ppmr_header, // sram starting address + (size_t) sizeof(G_ppmr_header), // size of copy + SSX_WAIT_FOREVER, // no timeout + NULL, // no call back + NULL, // no call back arguments + ASYNC_REQUEST_BLOCKING); // blocking request + + if(l_ssxrc != SSX_OK) + { + MAIN_TRAC_ERR("read_ppmr_header: BCDE request create failure rc=[%08X]", -l_ssxrc); + /* + * @errortype + * @moduleid READ_PPMR_HEADER + * @reasoncode SSX_GENERIC_FAILURE + * @userdata1 RC for BCE block-copy engine + * @userdata2 Internal function checkpoint + * @userdata4 ERC_BCE_REQUEST_CREATE_FAILURE + * @devdesc Failed to create BCDE request + */ + l_reasonCode = SSX_GENERIC_FAILURE; + l_extReasonCode = ERC_BCE_REQUEST_CREATE_FAILURE; + + userdata1 = (uint32_t)(-l_ssxrc); + break; + } + + // Do actual copying + l_ssxrc = bce_request_schedule(&pba_copy); + + if(l_ssxrc != SSX_OK) + { + MAIN_TRAC_ERR("read_ppmr_header: BCE request schedule failure rc=[%08X]", -l_ssxrc); + /* + * @errortype + * @moduleid READ_PPMR_HEADER + * @reasoncode SSX_GENERIC_FAILURE + * @userdata1 RC for BCE block-copy engine + * @userdata4 ERC_BCE_REQUEST_SCHEDULE_FAILURE + * @devdesc Failed to read PPMR data by using BCDE + */ + l_reasonCode = SSX_GENERIC_FAILURE; + l_extReasonCode = ERC_BCE_REQUEST_SCHEDULE_FAILURE; + + userdata1 = (uint32_t)(-l_ssxrc); + break; + } + + if(G_ppmr_header.oppb_length != sizeof(OCCPstateParmBlock)) + { + MAIN_TRAC_ERR("read_ppmr_header: OCCPstateParmBlock size mismatch:" + "PPMR header sz[0x%08x] PPMR struct sz[0x%08x]", + G_ppmr_header.oppb_length, sizeof(OCCPstateParmBlock)); + + /* + * @errortype + * @moduleid READ_PPMR_HEADER + * @reasoncode PGPE_FAILURE + * @userdata1 G_ppmr_header.oppb_length + * @userdata2 sizeof(OCCPstateParmBlock) + * @userdata4 ERC_PGPE_PPMR_OPPB_SIZE_MISMATCH + * @devdesc PPMR's OPPB size mismatches data structure's + */ + l_reasonCode = SSX_GENERIC_FAILURE; + l_extReasonCode = ERC_BCE_REQUEST_SCHEDULE_FAILURE; + + userdata1 = G_ppmr_header.oppb_length; + userdata2 = sizeof(OCCPstateParmBlock); + break; + } + + + + } while (0); + + if ( l_reasonCode ) + { + errlHndl_t l_errl = createErrl(READ_PPMR_HEADER, //modId + l_reasonCode, //reasoncode + l_extReasonCode, //Extended reason code + ERRL_SEV_UNRECOVERABLE, //Severity + NULL, //Trace Buf + 0, //Trace Size + userdata1, //userdata1 + userdata2); //userdata2 + + // Callout firmware + addCalloutToErrl(l_errl, + ERRL_CALLOUT_TYPE_COMPONENT_ID, + ERRL_COMPONENT_ID_FIRMWARE, + ERRL_CALLOUT_PRIORITY_HIGH); + + REQUEST_RESET(l_errl); + + return; + } + + // Read OCC pstates parameter block + read_oppb_params((OCCPstateParmBlock*)G_ppmr_header.oppb_offset); +} + +/* + * Function Specification + * + * Name: read_oppb_params + * + * Description: Read the OCC Pstates Parameter Block, + * and initializa Pstates Global Variables. + * + * End Function Specification + */ +void read_oppb_params(const OCCPstateParmBlock* oppb_offset) +{ + int l_ssxrc = SSX_OK; + uint32_t l_reasonCode = 0; + uint32_t l_extReasonCode = 0; + + create_tlb_entry( ((uint32_t)oppb_offset + (uint32_t)PPMR_ADDRESS_HOMER), + sizeof(OCCPstateParmBlock)); + + do{ + // use block copy engine to read the PPMR header + BceRequest pba_copy; + + // Set up a copy request + l_ssxrc = bce_request_create(&pba_copy, // block copy object + &G_pba_bcde_queue, // mainstore to sram copy engine + (uint32_t)PPMR_ADDRESS_HOMER + + (uint32_t)oppb_offset, // mainstore address + (uint32_t) &G_oppb, // sram starting address + (size_t) sizeof(OCCPstateParmBlock), // size of copy + SSX_WAIT_FOREVER, // no timeout + NULL, // no call back + NULL, // no call back arguments + ASYNC_REQUEST_BLOCKING); // blocking request + + if(l_ssxrc != SSX_OK) + { + CMDH_TRAC_ERR("read_oppb_params: BCDE request create failure rc=[%08X]", -l_ssxrc); + /* + * @errortype + * @moduleid READ_OPPB_PARAMS + * @reasoncode SSX_GENERIC_FAILURE + * @userdata1 RC for BCE block-copy engine + * @userdata2 Internal function checkpoint + * @userdata4 ERC_BCE_REQUEST_CREATE_FAILURE + * @devdesc Failed to create BCDE request + */ + l_reasonCode = SSX_GENERIC_FAILURE; + l_extReasonCode = ERC_BCE_REQUEST_CREATE_FAILURE; + break; + } + + // Do actual copying + l_ssxrc = bce_request_schedule(&pba_copy); + + if(l_ssxrc != SSX_OK) + { + CMDH_TRAC_ERR("read_oppb_params: BCE request schedule failure rc=[%08X]", -l_ssxrc); + /* + * @errortype + * @moduleid READ_OPPB_PARAMS + * @reasoncode SSX_GENERIC_FAILURE + * @userdata1 RC for BCE block-copy engine + * @userdata4 ERC_BCE_REQUEST_SCHEDULE_FAILURE + * @devdesc Failed to read PPMR data by using BCDE + */ + l_reasonCode = SSX_GENERIC_FAILURE; + l_extReasonCode = ERC_BCE_REQUEST_SCHEDULE_FAILURE; + break; + } + } while (0); + + if ( l_ssxrc != SSX_OK ) + { + errlHndl_t l_errl = createErrl(READ_OPPB_PARAMS, //modId + l_reasonCode, //reasoncode + l_extReasonCode, //Extended reason code + ERRL_SEV_UNRECOVERABLE, //Severity + NULL, //Trace Buf + 0, //Trace Size + -l_ssxrc, //userdata1 + 0); //userdata2 + + // Callout firmware + addCalloutToErrl(l_errl, + ERRL_CALLOUT_TYPE_COMPONENT_ID, + ERRL_COMPONENT_ID_FIRMWARE, + ERRL_CALLOUT_PRIORITY_HIGH); + + REQUEST_RESET(l_errl); + + return; + } + + // Copy over max frequency into G_proc_fmax_mhz + G_proc_fmax_mhz = G_oppb.frequency_max_khz / 1000; + + + // Used by amec for pcap calculation could use G_oppb.frequency_step_khz + // in PCAP calculationsinstead, but using a separate varaible speeds + // up PCAP relatedcalculations significantly, by eliminating slow + // division operations. + G_mhz_per_pstate = G_oppb.frequency_step_khz/1000; + + TRAC_INFO("read_oppb_params: OCC Pstates Parameter Block read successfully"); } /* @@ -971,11 +1254,44 @@ void Main_thread_routine(void *private) slave_occ_init(); CHECKPOINT(SLAVE_OCC_INITIALIZED); + // @TODO: remove this precompile directive check when PGPE code is integrated. + /// RTC: 163934 +#ifndef PGPE_SUPPORT + extern pstateStatus G_proc_pstate_status; + // TEMP Hack to enable Active State, until PGPE is ready + G_proc_pstate_status = PSTATES_ENABLED; + + + // Temp hack to Set up Key Globals for use by proc_freq2pstate functions + G_oppb.frequency_max_khz = 4322500; + G_oppb.frequency_min_khz = 2028250; + G_oppb.frequency_step_khz = 16667; + G_oppb.pstate_min = PMAX + + ((G_oppb.frequency_max_khz - G_oppb.frequency_min_khz)/G_oppb.frequency_step_khz); + + G_proc_fmax_mhz = G_oppb.frequency_max_khz / 1000; + + + // Set globals used by amec for pcap calculation + // could have used G_oppb.frequency_step_khz in PCAP calculations + // instead, but using a separate varaible speeds up PCAP related + // calculations significantly, by eliminating division operations. + G_mhz_per_pstate = G_oppb.frequency_step_khz/1000; + + TRAC_INFO("Main_thread_routine: Pstate Key globals initialized to default values"); + +#else // Read PGPE header file, extract OCC/PGPE Shared SRAM address and size, // Read other global parameters, e.g. G_pgpe_beacon_address, etc. read_pgpe_header(); CHECKPOINT(PGPE_IMAGE_HEADER_READ); + // Read PPMR header, extract OCC pstates parameter block address and size, + // Read OCCC pstate parameter block. + read_ppmr_header(); + CHECKPOINT(PPMR_IMAGE_HEADER_READ); +#endif + // Initialize watchdog timers. This needs to be right before // start rtl to make sure timer doesn't timeout. This timer is being // reset from the rtl task. diff --git a/src/occ_405/occLinkInputFile b/src/occ_405/occLinkInputFile index 16dbd5fa..21b5a3fc 100644 --- a/src/occ_405/occLinkInputFile +++ b/src/occ_405/occLinkInputFile @@ -60,6 +60,7 @@ INPUT ( amec_amester.o occhw_irq_init.o occhw_ocb.o occhw_pba.o + pgpe_interface.o ppc405_boot.o ppc405_breakpoint.o ppc405_cache_core.o @@ -73,6 +74,7 @@ INPUT ( amec_amester.o ppc405_mmu_asm.o ppc405_thread_init.o proc_data.o + proc_data_control.o proc_pstate.o reset.o rtls_tables.o diff --git a/src/occ_405/occ_service_codes.h b/src/occ_405/occ_service_codes.h index b96ff0d0..6633ba5b 100644 --- a/src/occ_405/occ_service_codes.h +++ b/src/occ_405/occ_service_codes.h @@ -113,11 +113,17 @@ enum occReasonCode DIMM_GPE_FAILURE = 0xD0, MEMORY_INIT_FAILED = 0xD1, DIMM_INVALID_STATE = 0xD2, - PGPE_BEACON_TIMEOUT = 0xD3, + + // PGPE Generic RC + PGPE_FAILURE = 0xD3, + /// GPE IPC TASK RCs GPE_REQUEST_CREATE_FAILURE = 0xD4, GPE_REQUEST_SCHEDULE_FAILURE = 0xD5, GPE_REQUEST_TASK_TIMEOUT = 0xD6, + GPR_REQUEST_RC_FAILURE = 0xD7, + + INVALID_MAGIC_NUMBER = 0xDA, /// Success! OCC_SUCCESS_REASON_CODE = 0xFF, @@ -227,6 +233,13 @@ enum occExtReasonCode ERC_AVSBUS_VDN_VOLTAGE_FAILURE = 0x00AC, ERC_AVSBUS_VDN_CURRENT_FAILURE = 0x00AD, + ERC_PGPE_BEACON_TIMEOUT = 0x00B0, + ERC_PGPE_NOT_IDLE = 0x00B1, + ERC_PGPE_UNSUCCESSFULL = 0x00B2, + ERC_PGPE_START_FAILURE = 0x00B3, + ERC_PGPE_SUSPEND_FAILURE = 0x00B4, + ERC_PGPE_CLIP_FAILURE = 0x00B5, + ERC_PGPE_PPMR_OPPB_SIZE_MISMATCH = 0x00B6, }; // Error log Module Ids @@ -249,6 +262,10 @@ enum occModuleId CMDH_DBUG_MID = MAIN_COMP_ID | 0x0f, I2C_LOCK_UPDATE = MAIN_COMP_ID | 0x10, CREATE_TLB_ENTRY = MAIN_COMP_ID | 0x11, + READ_PGPE_HEADER = MAIN_COMP_ID | 0x12, + READ_PPMR_HEADER = MAIN_COMP_ID | 0x13, + READ_OPPB_PARAMS = MAIN_COMP_ID | 0x14, + MAIN_SMGR_MID = MAIN_COMP_ID | 0x15, }; enum occUserDataType diff --git a/src/occ_405/occ_sys_config.h b/src/occ_405/occ_sys_config.h index 9380cfb6..6b85d7c6 100755 --- a/src/occ_405/occ_sys_config.h +++ b/src/occ_405/occ_sys_config.h @@ -40,6 +40,7 @@ #define MAX_NUM_NODES 4 #define MAX_NUM_CORES 24 #define MAX_NUM_QUADS 6 +#define NUM_CORES_PER_QUAD 4 #define MAX_THREADS_PER_CORE 4 #define MAX_NUM_CHIP_MODULES 4 #define MAX_NUM_POWER_SUPPLIES 4 diff --git a/src/occ_405/pgpe/pgpe_interface.c b/src/occ_405/pgpe/pgpe_interface.c new file mode 100644 index 00000000..bbdf8018 --- /dev/null +++ b/src/occ_405/pgpe/pgpe_interface.c @@ -0,0 +1,812 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/occ_405/pgpe/pgpe_interface.c $ */ +/* */ +/* OpenPOWER OnChipController Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2011,2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ + + +#include "occ_common.h" +#include "occhw_async.h" +#include "pgpe_interface.h" +#include "pstate_pgpe_occ_api.h" +#include "occ_service_codes.h" +#include "pgpe_service_codes.h" +#include "trac.h" +#include "state.h" +#include "proc_pstate.h" +#include "proc_data_control.h" +#include "occ_sys_config.h" + +extern opal_static_table_t G_opal_static_table; + +extern pstateStatus G_proc_pstate_status; +extern PMCR_OWNER G_proc_pmcr_owner; + +extern uint16_t G_proc_fmax_mhz; + +extern GPE_BUFFER(PstatesClips* G_core_data_control_gpewrite_ptr); +extern GPE_BUFFER(PstatesClips* G_core_data_control_occwrite_ptr); + +// IPC GPE Requests +GpeRequest G_clip_update_req; +GpeRequest G_pmcr_set_req; +GpeRequest G_start_suspend_req; +GpeRequest G_wof_control_req; +GpeRequest G_wof_vfrt_req; + +// The the GPE parameter fields for PGPE IPC calls. +GPE_BUFFER(ipcmsg_clip_update_t* G_clip_update_parms_ptr); +GPE_BUFFER(ipcmsg_set_pmcr_t* G_pmcr_set_parms_ptr); +GPE_BUFFER(ipcmsg_start_suspend_t G_start_suspend_parms); +GPE_BUFFER(ipcmsg_wof_control_t G_wof_control_parms); +GPE_BUFFER(ipcmsg_wof_vfrt_t G_wof_vfrt_parms); + + +// Function Specification +// +// Name: init_pgpe_ipcs +// +// Description: Create all PGPE IPC messages. +// +// End Function Specification + +errlHndl_t init_pgpe_ipcs(void) +{ + errlHndl_t err = NULL; // Error handler + + //Set PMCR IPC task parameters to gpewrite's quad pstates data structure + G_pmcr_set_parms_ptr = &G_core_data_control_gpewrite_ptr->pstates; + + //Set Clip IPC task parameters to gpewrite's quad pstates data structure + G_clip_update_parms_ptr = &G_core_data_control_gpewrite_ptr->clips; + + do + { + err = pgpe_init_clips(); + if(err) + { + break; + } + err = pgpe_init_pmcr(); + if(err) + { + break; + } + err = pgpe_init_start_suspend(); + if(err) + { + break; + } + err = pgpe_init_wof_control(); + if(err) + { + break; + } + err = pgpe_init_wof_vfrt(); + }while(0); + + if(err) + { + REQUEST_RESET(err); + } + + // Initialization used in the task_core_data_control for PGPE success + // checks made before the first clip/pstate IPC message to be ever sent + // from either of the two double buffers. + G_core_data_control_occwrite_ptr->clips.msg_cb.rc = PGPE_RC_SUCCESS; + G_core_data_control_occwrite_ptr->pstates.msg_cb.rc = PGPE_RC_SUCCESS; + + G_core_data_control_gpewrite_ptr->clips.msg_cb.rc = PGPE_RC_SUCCESS; + G_core_data_control_gpewrite_ptr->pstates.msg_cb.rc = PGPE_RC_SUCCESS; + + + return(err); +} + + +// Function Specification +// +// Name: pgpe_init_clips +// +// Description: Create PGPE clip update IPC messages (non-blocking). +// +// End Function Specification + +errlHndl_t pgpe_init_clips(void) +{ + int rc; // return code + errlHndl_t err = NULL; // Error handler + + do + { + //Initializes the GpeRequest object for pgpe clips setting IPC + rc = gpe_request_create(&G_clip_update_req, // GpeRequest for the task + &G_async_gpe_queue2, // Queue + IPC_MSGID_405_CLIPS, // Function ID + G_clip_update_parms_ptr, // Task parameters + SSX_WAIT_FOREVER, // Timeout (none) + NULL, // Callback + NULL, // Callback arguments + ASYNC_CALLBACK_IMMEDIATE ); // Options + + if( rc ) + { + // If we failed to create the GpeRequest then there is a serious problem. + MAIN_TRAC_ERR("pgpe_init_clips: Failure creating the " + "IPC_MSGID_405_CLIPS GpeRequest. [RC=0x%08x]", rc ); + + /* + * @errortype + * @moduleid PGPE_INIT_CLIPS_MOD + * @reasoncode GPE_REQUEST_CREATE_FAILURE + * @userdata1 gpe_request_create return code + * @userdata4 OCC_NO_EXTENDED_RC + * @devdesc Failure to create clips GpeRequest object + */ + err = createErrl( + PGPE_INIT_CLIPS_MOD, //ModId + GPE_REQUEST_CREATE_FAILURE, //Reasoncode + OCC_NO_EXTENDED_RC, //Extended reason code + ERRL_SEV_PREDICTIVE, //Severity + NULL, //Trace Buf + DEFAULT_TRACE_SIZE, //Trace Size + rc, //Userdata1 + 0 //Userdata2 + ); + } + + } while (0); + + return(err); +} + +// Function Specification +// +// Name: pgpe_init_pmcr +// +// Description: Create PGPE PMCR set IPC messages (non-blocking). +// +// End Function Specification + +errlHndl_t pgpe_init_pmcr(void) +{ + int rc; // return code + errlHndl_t err = NULL; // Error handler + + do + { + //Initializes the GpeRequest object for pgpe PMCR setting IPC + rc = gpe_request_create(&G_pmcr_set_req, // GpeRequest for the task + &G_async_gpe_queue2, // Queue + IPC_MSGID_405_SET_PMCR, // Function ID + G_pmcr_set_parms_ptr, // Task parameters + SSX_WAIT_FOREVER, // Timeout (none) + NULL, // Callback + NULL, // Callback arguments + ASYNC_CALLBACK_IMMEDIATE); // Options + + if( rc ) + { + // If we failed to create the GpeRequest then there is a serious problem. + MAIN_TRAC_ERR("pgpe_init_pmcr: Failure creating the " + "IPC_MSGID_405_SET_PMCR GpeRequest. [RC=0x%08x]", + rc ); + + /* + * @errortype + * @moduleid PGPE_INIT_PMCR_MOD + * @reasoncode GPE_REQUEST_CREATE_FAILURE + * @userdata1 gpe_request_create return code + * @userdata4 OCC_NO_EXTENDED_RC + * @devdesc Failure to create pmcr GpeRequest object + */ + err = createErrl( + PGPE_INIT_PMCR_MOD, //ModId + GPE_REQUEST_CREATE_FAILURE, //Reasoncode + OCC_NO_EXTENDED_RC, //Extended reason code + ERRL_SEV_PREDICTIVE, //Severity + NULL, //Trace Buf + DEFAULT_TRACE_SIZE, //Trace Size + rc, //Userdata1 + 0 //Userdata2 + ); + } + + } while (0); + + return(err); +} + +// Function Specification +// +// Name: pgpe_init_start_suspend +// +// Description: Create PGPE start/suspend IPC messages (blocking). +// +// End Function Specification + +errlHndl_t pgpe_init_start_suspend(void) +{ + int rc; // return code + errlHndl_t err = NULL; // Error handler + + do + { + //Initializes the GpeRequest object for pgpe start/suspend IPC + rc = gpe_request_create(&G_start_suspend_req, // GpeRequest for the task + &G_async_gpe_queue2, // Queue + IPC_MSGID_405_START_SUSPEND, // Function ID + &G_start_suspend_parms, // Task parameters + SSX_WAIT_FOREVER, // Timeout (none) + (AsyncRequestCallback)pgpe_start_suspend_callback, // Callback + NULL, // Callback arguments + ASYNC_CALLBACK_IMMEDIATE ); // Options + + if( rc ) + { + // If we failed to create the GpeRequest then there is a serious problem. + MAIN_TRAC_ERR("pgpe_init_start_suspend: Failure creating the " + "IPC_MSGID_405_START_SUSPEND GpeRequest. [RC=0x%08x]", + rc ); + + /* + * @errortype + * @moduleid PGPE_INIT_START_SUSPEND_MOD + * @reasoncode GPE_REQUEST_CREATE_FAILURE + * @userdata1 gpe_request_create return code + * @userdata4 OCC_NO_EXTENDED_RC + * @devdesc Failure to create start_suspend GpeRequest object + */ + err = createErrl( + PGPE_INIT_START_SUSPEND_MOD, //ModId + GPE_REQUEST_CREATE_FAILURE, //Reasoncode + OCC_NO_EXTENDED_RC, //Extended reason code + ERRL_SEV_PREDICTIVE, //Severity + NULL, //Trace Buf + DEFAULT_TRACE_SIZE, //Trace Size + rc, //Userdata1 + 0 //Userdata2 + ); + } + + } while (0); + + return(err); +} + + +// Function Specification +// +// Name: pgpe_init_wof_control +// +// Description: Create PGPE WOF control IPC messages (non-blocking). +// +// End Function Specification + +errlHndl_t pgpe_init_wof_control(void) +{ + int rc; // return code + errlHndl_t err = NULL; // Error handler + + do + { + //Initializes the GpeRequest object for pgpe wof control IPC + rc = gpe_request_create(&G_wof_control_req, // GpeRequest for the task + &G_async_gpe_queue2, // Queue + IPC_MSGID_405_WOF_CONTROL, // Function ID + &G_wof_control_parms, // Task parameters + SSX_WAIT_FOREVER, // Timeout (none) + NULL, // Callback + NULL, // Callback arguments + ASYNC_CALLBACK_IMMEDIATE); // Options + + if( rc ) + { + // If we failed to create the GpeRequest then there is a serious problem. + MAIN_TRAC_ERR("pgpe_init_wof_control: Failure creating the " + "IPC_MSGID_405_WOF_CONTROL GpeRequest. [RC=0x%08x]", + rc ); + + /* + * @errortype + * @moduleid PGPE_INIT_WOF_CONTROL_MOD + * @reasoncode GPE_REQUEST_CREATE_FAILURE + * @userdata1 gpe_request_create return code + * @userdata4 OCC_NO_EXTENDED_RC + * @devdesc Failure to create wof control GpeRequest object + */ + err = createErrl( + PGPE_INIT_WOF_CONTROL_MOD, //ModId + GPE_REQUEST_CREATE_FAILURE, //Reasoncode + OCC_NO_EXTENDED_RC, //Extended reason code + ERRL_SEV_PREDICTIVE, //Severity + NULL, //Trace Buf + DEFAULT_TRACE_SIZE, //Trace Size + rc, //Userdata1 + 0 //Userdata2 + ); + } + + } while (0); + + return(err); +} + +// Function Specification +// +// Name: pgpe_init_wof_vfrt +// +// Description: Create PGPE WOF vfrt IPC messages (non-blocking). +// +// End Function Specification + +errlHndl_t pgpe_init_wof_vfrt(void) +{ + int rc; // return code + errlHndl_t err = NULL; // Error handler + + do + { + //Initializes the GpeRequest object for pgpe wof vfrt IPC + rc = gpe_request_create(&G_wof_vfrt_req, // GpeRequest for the task + &G_async_gpe_queue2, // Queue + IPC_MSGID_405_WOF_VFRT, // Function ID + &G_wof_vfrt_parms, // Task parameters + SSX_WAIT_FOREVER, // Timeout (none) + NULL, // Callback + NULL, // Callback arguments + ASYNC_CALLBACK_IMMEDIATE); // Options + + if( rc ) + { + // If we failed to create the GpeRequest then there is a serious problem. + MAIN_TRAC_ERR("pgpe_init_wof_vfrt: Failure creating the " + "IPC_MSGID_405_WOF_VFRT GpeRequest. [RC=0x%08x]", + rc ); + + /* + * @errortype + * @moduleid PGPE_INIT_WOF_VFRT_MOD + * @reasoncode GPE_REQUEST_CREATE_FAILURE + * @userdata1 gpe_request_create return code + * @userdata4 OCC_NO_EXTENDED_RC + * @devdesc Failure to create wof control GpeRequest object + */ + err = createErrl( + PGPE_INIT_WOF_VFRT_MOD, //ModId + GPE_REQUEST_CREATE_FAILURE, //Reasoncode + OCC_NO_EXTENDED_RC, //Extended reason code + ERRL_SEV_PREDICTIVE, //Severity + NULL, //Trace Buf + DEFAULT_TRACE_SIZE, //Trace Size + rc, //Userdata1 + 0 //Userdata2 + ); + } + + } while (0); + + return(err); +} + + +// Function Specification +// +// Name: pgpe_widen_clip_ranges +// +// Description: Wide open PGPE clip ranges. Since this IPC call +// is non-blocking, this routine has to assure call +// completion before checking the pgpe return value. +// +// End Function Specification + +errlHndl_t pgpe_widen_clip_ranges(void) +{ + + errlHndl_t err = NULL; // Error handler + uint8_t i; // Loop variable + + // Set clip bounds wide open + for(i=0; ips_val_clip_min[i] = pmin_rail(); + + // maximum pstate: + G_clip_update_parms_ptr->ps_val_clip_max[i] = proc_freq2pstate(G_proc_fmax_mhz); + } + + // Check that no previous clip update calls are still in progress + if(async_request_is_idle(&G_clip_update_req.request)) + { + // will check for this IPC completion at transition to active state + err = pgpe_clip_update(); + } + else + { + // an earlier clip update IPC call has not completed, trace and log an error + TRAC_ERR("pgpe_widen_clip_ranges: clip update IPC task is not Idle"); + + // log an error + MAIN_TRAC_ERR("pgpe_widen_clip_ranges: clip update IPC is not Idle"); + + /* + * @errortype + * @moduleid PGPE_WIDEN_CLIP_RANGES_MOD + * @reasoncode PGPE_FAILURE + * @userdata1 0 + * @userdata4 ERC_PGPE_NOT_IDLE + * @devdesc pgpe clip update not idle + */ + err = createErrl( + PGPE_WIDEN_CLIP_RANGES_MOD, //ModId + PGPE_FAILURE, //Reasoncode + OCC_NO_EXTENDED_RC, //Extended reason code + ERRL_SEV_PREDICTIVE, //Severity + NULL, //Trace Buf + DEFAULT_TRACE_SIZE, //Trace Size + 0, //Userdata1 + 0 //Userdata2 + ); + } + + return(err); +} + +// Function Specification +// +// Name: pgpe_clip_update +// +// Description: call PGPE IPC to update clip ranges. Since this IPC call is +// non-blocking, the calling function needs to assure previous +// call completion before calling this call. +// +// End Function Specification + +errlHndl_t pgpe_clip_update(void) +{ + int rc; // gpe schedule return code + errlHndl_t err = NULL; // Error handler + + do + { + // Caller must check the completion of previous invocation of clip updates. + // This check is a safety feature in case caller didn't check IPC is idle. + if(!async_request_is_idle(&G_clip_update_req.request)) + { + // an earlier clip update IPC call has not completed, trace and log an error + TRAC_ERR("pgpe_clip_update: clip update IPC task is not Idle"); + + /* + * @errortype + * @moduleid PGPE_CLIP_UPDATE_MOD + * @reasoncode PGPE_FAILURE + * @userdata1 0 + * @userdata4 ERC_PGPE_NOT_IDLE + * @devdesc pgpe clip update not idle + */ + err = createErrl( + PGPE_CLIP_UPDATE_MOD, //ModId + PGPE_FAILURE, //Reasoncode + ERC_PGPE_NOT_IDLE, //Extended reason code + ERRL_SEV_PREDICTIVE, //Severity + NULL, //Trace Buf + DEFAULT_TRACE_SIZE, //Trace Size + 0, //Userdata1 + 0 //Userdata2 + ); + + break; + } + + // @TODO: remove this precompile directive check when PGPE code is integrated. + // RTC: 163934 +#ifdef PGPE_SUPPORT + // Schedule PGPE clip update IPC task + rc = gpe_request_schedule(&G_clip_update_req); +#else + G_start_suspend_parms.msg_cb.rc = PGPE_RC_SUCCESS; + rc = 0; +#endif + // Confirm Successfull completion of PGPE clip update task + if(rc != 0) + { + //Error in scheduling pgpe clip update task + TRAC_ERR("pgpe_clip_update: Failed to schedule clip update pgpe task rc=%x", + rc); + + /* @ + * @errortype + * @moduleid PGPE_CLIP_UPDATE_MOD + * @reasoncode GPE_REQUEST_SCHEDULE_FAILURE + * @userdata1 rc - gpe_request_schedule return code + * @userdata2 0 + * @userdata4 OCC_NO_EXTENDED_RC + * @devdesc OCC Failed to schedule a GPE job for clip update + */ + err = createErrl( + PGPE_CLIP_UPDATE_MOD, // modId + GPE_REQUEST_SCHEDULE_FAILURE, // reasoncode + OCC_NO_EXTENDED_RC, // Extended reason code + ERRL_SEV_UNRECOVERABLE, // Severity + NULL, // Trace Buf + DEFAULT_TRACE_SIZE, // Trace Size + rc, // userdata1 + 0 // userdata2 + ); + + REQUEST_RESET(err); //This will add a firmware callout for us + } + }while(0); + + return err; +} + + +// Function Specification +// +// Name: start_suspend_callback +// +// Description: callback function for the pgpe_start_suspend IPC function +// gets called after the PGPE IPC enables/disables pstates. +// Upon successful completion, it sets/clears the G_proc_pstate_status +// flag to indicat whether it is enabled/disabled/in-transition. +// +// End Function Specification + +void pgpe_start_suspend_callback(void) +{ + int pgpe_rc; // pgpe return codes + errlHndl_t err = NULL; // Error handler + + pgpe_rc = G_start_suspend_parms.msg_cb.rc; + + do + { + // Confirm Successfull completion of PGPE clup update task + if(pgpe_rc != PGPE_RC_SUCCESS) + { + //Error in scheduling pgpe clip update task + + /* @ + * @errortype + * @moduleid PGPE_START_SUSPEND_CALLBACK_MOD + * @reasoncode GPE_REQUEST_SCHEDULE_FAILURE + * @userdata1 pgpe_rc - PGPE return code + * @userdata4 OCC_NO_EXTENDED_RC + * @devdesc OCC Failed to schedule a GPE job for start_suspend + */ + err = createErrl( + PGPE_START_SUSPEND_CALLBACK_MOD, // modId + PGPE_FAILURE, // reasoncode + ERC_PGPE_UNSUCCESSFULL, // Extended reason code + ERRL_SEV_UNRECOVERABLE, // Severity + NULL, // Trace Buf + DEFAULT_TRACE_SIZE, // Trace Size + pgpe_rc, // userdata1 + 0 // userdata2 + ); + + REQUEST_RESET(err); //This will add a firmware callout for us + break; + } + // task completed successfully + else + { + // this was a command to enable pstates + if(G_start_suspend_parms.action == PGPE_ACTION_PSTATE_START) + { + // Pstates are now enabled (enable Active State transition). + G_proc_pstate_status = PSTATES_ENABLED; + } + // this was a command to disable pstates + else if(G_start_suspend_parms.action == PGPE_ACTION_PSTATE_SUSPEND) + { + // Pstates are now disabled (disaable Active State transition). + G_proc_pstate_status = PSTATES_DISABLED; + } + + G_proc_pmcr_owner = G_start_suspend_parms.pmcr_owner; + } + + } while(0); + +} + +// Function Specification +// +// Name: pgpe_start_suspend +// +// Description: Schedule a PGPE IPC to enable/disable pstates. This will also tell +// PGPE how to set PMCR mode register (OCC/OPAL control pstates). +// when this IPC is successfully scheduled, it sets the G_proc_pstate_status +// global variable to in-transition, a call back function +// (pgpe_start_suspend_callback) will set it to the appropriate value upon +// successfull completion. +// +// End Function Specification + +errlHndl_t pgpe_start_suspend(uint8_t action) +{ + PMCR_OWNER owner; // PMCR owner + int rc; // gpe schedule return codes + errlHndl_t err = NULL; // Error handler + + // For now, we set PMCR ownership based on whether the system + // is OPAL system or not. + if(G_sysConfigData.system_type.kvm) + { + owner = PMCR_OWNER_HOST; + } + else + { + owner = PMCR_OWNER_OCC; + } + + // set the IPC parameters + G_start_suspend_parms.action = action; + G_start_suspend_parms.pmcr_owner = owner; + + // @TODO: remove this precompile directive check when PGPE code is integrated. + // RTC: 163934 +#ifdef PGPE_SUPPORT + // Schedule PGPE start_suspend task + rc = gpe_request_schedule(&G_start_suspend_req); +#else + rc = 0; +#endif + + // couldn't schedule the IPC task? + if(rc != 0) + { + //Error in scheduling pgpe clip update task + TRAC_ERR("pgpe_start_suspend: Failed to schedule pgpe start_suspend task rc=%x", + rc); + /* @ + * @errortype + * @moduleid PGPE_START_SUSPEND_MOD + * @reasoncode GPE_REQUEST_SCHEDULE_FAILURE + * @userdata1 rc - gpe_request_schedule return code + * @userdata4 OCC_NO_EXTENDED_RC + * @devdesc OCC Failed to schedule a GPE job for start_suspend + */ + err = createErrl( + PGPE_START_SUSPEND_MOD, // modId + GPE_REQUEST_SCHEDULE_FAILURE, // reasoncode + OCC_NO_EXTENDED_RC, // Extended reason code + ERRL_SEV_UNRECOVERABLE, // Severity + NULL, // Trace Buf + DEFAULT_TRACE_SIZE, // Trace Size + rc, // userdata1 + 0 // userdata2 + ); + + REQUEST_RESET(err); //This will add a firmware callout for us + } + // successfully scheduled, set the G_proc_pstate_status to indicate transition + else + { + G_proc_pstate_status = PSTATES_IN_TRANSITION; + } + +#ifndef PGPE_SUPPORT + pgpe_start_suspend_callback(); +#endif + + return err; +} + + +// Function Specification +// +// Name: pgpe_pmcr_set +// +// Description: call PGPE IPC to set the PMCR with the pstate values. +// Since this IPC call is non-blocking, the calling +// function needs to assure previous call completion +// before calling this call. +// +// End Function Specification + +errlHndl_t pgpe_pmcr_set(void) +{ + int rc; // gpe schedule return codes + errlHndl_t err = NULL; // Error handler + + do + { + // Caller must check the completion of previous invocation of pmcr set IPC call. + // This check is a safety feature in case caller didn't check IPC is idle. + if(!async_request_is_idle(&G_pmcr_set_req.request)) + { + // an earlier clip update IPC call has not completed, trace and log an error + TRAC_ERR("pgpe_pmcr_set: clip update IPC task is not Idle"); + + /* + * @errortype + * @moduleid PGPE_PMCR_SET_MOD + * @reasoncode PGPE_FAILURE + * @userdata1 0 + * @userdata4 ERC_PGPE_NOT_IDLE + * @devdesc pgpe pmcr set not idle + */ + err = createErrl( + PGPE_PMCR_SET_MOD, //ModId + PGPE_FAILURE, //Reasoncode + ERC_PGPE_NOT_IDLE, //Extended reason code + ERRL_SEV_PREDICTIVE, //Severity + NULL, //Trace Buf + DEFAULT_TRACE_SIZE, //Trace Size + 0, //Userdata1 + 0 //Userdata2 + ); + + break; + } + + // @TODO: remove this precompile directive check when PGPE code is integrated. + // RTC: 163934 +#ifdef PGPE_SUPPORT + // Schedule PGPE clip update IPC task + rc = gpe_request_schedule(&G_pmcr_set_req); +#else + rc = 0; +#endif + + // Confirm Successfull completion of PGPE clup update task + if(rc != 0) + { + //Error in scheduling pgpe clip update task + TRAC_ERR("pgpe_pmcr_set: Failed to schedule PMCR setup pgpe task rc=%x", + rc); + } + + if(rc != 0) + { + /* @ + * @errortype + * @moduleid PGPE_PMCR_SET_MOD + * @reasoncode GPE_REQUEST_SCHEDULE_FAILURE + * @userdata1 rc - gpe_request_schedule return code + * @userdata2 0 + * @userdata4 OCC_NO_EXTENDED_RC + * @devdesc OCC Failed to schedule a GPE job for clip update + */ + err = createErrl( + PGPE_PMCR_SET_MOD, // modId + GPE_REQUEST_SCHEDULE_FAILURE, // reasoncode + OCC_NO_EXTENDED_RC, // Extended reason code + ERRL_SEV_UNRECOVERABLE, // Severity + NULL, // Trace Buf + DEFAULT_TRACE_SIZE, // Trace Size + rc, // userdata1 + 0 // userdata2 + ); + + REQUEST_RESET(err); //This will add a firmware callout for us + } + } + while(0); + + return err; +} + diff --git a/src/occ_405/pgpe/pgpe_interface.h b/src/occ_405/pgpe/pgpe_interface.h new file mode 100644 index 00000000..a777f28d --- /dev/null +++ b/src/occ_405/pgpe/pgpe_interface.h @@ -0,0 +1,45 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/occ_405/pgpe/pgpe_interface.h $ */ +/* */ +/* OpenPOWER OnChipController Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2011,2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ + +#ifndef _PGPE_INTERFACE_H_ +#define _PGPE_INTERFACE_H_ + +#include "errl.h" + +errlHndl_t init_pgpe_ipcs(void); + +errlHndl_t pgpe_init_clips(void); +errlHndl_t pgpe_init_pmcr(void); +errlHndl_t pgpe_init_start_suspend(void); +errlHndl_t pgpe_init_wof_control(void); +errlHndl_t pgpe_init_wof_vfrt(void); + +errlHndl_t pgpe_widen_clip_ranges(void); +errlHndl_t pgpe_clip_update(void); +errlHndl_t pgpe_pmcr_set(void); +errlHndl_t pgpe_start_suspend(uint8_t action); +void pgpe_start_suspend_callback(void); + +#endif /* #ifndef _PGPE_INTERFACE_H_ */ diff --git a/src/occ_405/pgpe/pgpe_service_codes.h b/src/occ_405/pgpe/pgpe_service_codes.h new file mode 100644 index 00000000..2e669523 --- /dev/null +++ b/src/occ_405/pgpe/pgpe_service_codes.h @@ -0,0 +1,46 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/occ_405/pgpe/pgpe_service_codes.h $ */ +/* */ +/* OpenPOWER OnChipController Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2011,2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ + +#ifndef _PGPE_SERVICE_CODES_H_ +#define _PGPE_SERVICE_CODES_H_ + +#include + +enum pgpeModuleId +{ + PGPE_INIT_CLIPS_MOD = PGPE_COMP_ID | 0x00, + PGPE_INIT_PMCR_MOD = PGPE_COMP_ID | 0x01, + PGPE_INIT_START_SUSPEND_MOD = PGPE_COMP_ID | 0x02, + PGPE_INIT_WOF_CONTROL_MOD = PGPE_COMP_ID | 0x03, + PGPE_INIT_WOF_VFRT_MOD = PGPE_COMP_ID | 0x04, + PGPE_CLIP_UPDATE_MOD = PGPE_COMP_ID | 0x05, + PGPE_START_SUSPEND_MOD = PGPE_COMP_ID | 0x06, + PGPE_PMCR_SET_MOD = PGPE_COMP_ID | 0x07, + PGPE_WIDEN_CLIP_RANGES_MOD = PGPE_COMP_ID | 0x08, + PGPE_START_SUSPEND_CALLBACK_MOD = PGPE_COMP_ID | 0x09, +}; + + +#endif /* #ifndef _PGPE_SERVICE_CODES_H_ */ diff --git a/src/occ_405/pgpe_shared.h b/src/occ_405/pgpe/pgpe_shared.h similarity index 70% rename from src/occ_405/pgpe_shared.h rename to src/occ_405/pgpe/pgpe_shared.h index 0dac88fb..eb4b27a5 100644 --- a/src/occ_405/pgpe_shared.h +++ b/src/occ_405/pgpe/pgpe_shared.h @@ -1,7 +1,7 @@ /* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ -/* $Source: src/occ_405/pgpe_shared.h $ */ +/* $Source: src/occ_405/pgpe/pgpe_shared.h $ */ /* */ /* OpenPOWER OnChipController Project */ /* */ @@ -26,6 +26,8 @@ #define PGPE_HEADER_ADDR 0xFFF20180 // 0xfff20000 + 0x180 #define PGPE_HEADER_SZ 96 // Size of PGPE Image header +#define PGPE_MAGIC_NUMBER 0x5849502050475045ull // "XIP PGPE" + // Offset addresses of PGPE Header parameters (relative to start address) #define PGPE_SHARED_SRAM_ADDR_OFFSET 0x0c #define PGPE_SHARED_SRAM_SZ_OFFSET 0x14 @@ -40,3 +42,32 @@ // A pointer to PGPE Beacon Address #define PGPE_BEACON_ADDR_PTR (PGPE_HEADER_ADDR + PGPE_BEACON_ADDR_OFFSET) + +// PMMR (Pstates PM region) in HOMMR +#define PPMR_OPPM_ADDR_OFFSET 0x40 //offset of the OCC Pstates Parameter Block address in the PPMR header +#define PPMR_OPPM_SZ_OFFSET 0x44 //offset of the OCC Pstates Parameter Block size in the PPMR header + + +// This size must be a multiple of 128 +typedef struct __attribute__ ((packed)) +{ + uint64_t magic_number; + uint32_t bc_offset; + uint32_t resserved; + uint32_t bl_offset; + uint32_t bl_length; + uint32_t build_date;; + uint32_t version; + uint8_t resvd_flag[8]; + uint32_t pgpe_hcode_offset; + uint32_t pgpe_hcode_length; + uint32_t gppb_offset; + uint32_t gppb_length; + uint32_t lppb_offset; + uint32_t lppb_length; + uint32_t oppb_offset; + uint32_t oppb_length; + uint32_t pstables_offset; + uint32_t pstables_length; + uint8_t pad[48]; +} ppmr_header_t __attribute__ ((aligned (128))); diff --git a/src/occ_405/proc/proc_data.c b/src/occ_405/proc/proc_data.c index 0a0b5284..4de69256 100755 --- a/src/occ_405/proc/proc_data.c +++ b/src/occ_405/proc/proc_data.c @@ -35,6 +35,7 @@ #include "apss.h" #include "state.h" #include "proc_data_control.h" +#include "pgpe_interface.h" #include "cmdh_fsp.h" #include "sensor.h" @@ -319,7 +320,8 @@ void proc_core_init( void ) // cores are present and configured. The Core Configuration Status Register // has this information, so we will need to read it over OCI. uint64_t l_ccsr_val = in64(OCB_CCSR); - MAIN_TRAC_INFO("proc_core_init: CCSR read 0x%08X%08X", (uint32_t) (l_ccsr_val>>32), (uint32_t) l_ccsr_val); + MAIN_TRAC_INFO("proc_core_init: CCSR read 0x%08X%08X", + (uint32_t) (l_ccsr_val>>32), (uint32_t) l_ccsr_val); G_present_hw_cores = ((uint32_t) (l_ccsr_val >> 32)) & HW_CORES_MASK; G_present_cores = G_present_hw_cores; @@ -405,9 +407,8 @@ void proc_core_init( void ) } while(0); - // Initialize the core data control structures at the same time -// TEMP/TODO: Needs to be re-enabled when the data control task is enabled -// proc_core_data_control_init(); + // Initialize the core data control at the same time + init_pgpe_ipcs(); return; } diff --git a/src/occ_405/proc/proc_data_control.c b/src/occ_405/proc/proc_data_control.c index c68b4223..38165ac2 100755 --- a/src/occ_405/proc/proc_data_control.c +++ b/src/occ_405/proc/proc_data_control.c @@ -24,6 +24,7 @@ /* IBM_PROLOG_END_TAG */ #include "proc_data.h" +#include "proc_data_control.h" #include "occhw_async.h" #include "threadSch.h" #include "pmc_register_addresses.h" @@ -35,231 +36,147 @@ #include "apss.h" #include "state.h" #include "occ_sys_config.h" +#include "p9_pstates_common.h" +#include "pgpe_interface.h" +#include "rtls_service_codes.h" -// Pore flex request for GPE job. The initialization will be done one time -// during pore flex create. -PoreFlex G_core_data_control_req; +// The the GPE parameter fields for PGPE IPC calls. +extern GPE_BUFFER(ipcmsg_clip_update_t* G_clip_update_parms_ptr); +extern GPE_BUFFER(ipcmsg_set_pmcr_t* G_pmcr_set_parms_ptr); -// Global double buffering for core data control -GPE_BUFFER(PcbsPstateRegs G_core_data_control_a[MAX_NUM_HW_CORES]) = {{{0}}}; -GPE_BUFFER(PcbsPstateRegs G_core_data_control_b[MAX_NUM_HW_CORES]) = {{{0}}}; - -// Pointer to the core data control that will be used by GPE engine. -GPE_BUFFER(PcbsPstateRegs * G_core_data_control_gpewrite_ptr) = { &G_core_data_control_a[0] }; - -// Pointer to the core data control that will be written to by the OCC FW. -GPE_BUFFER(PcbsPstateRegs * G_core_data_control_occwrite_ptr) = { &G_core_data_control_b[0] }; +extern GpeRequest G_clip_update_req; +extern GpeRequest G_pmcr_set_req; -// The Gpe parameter fields are set up each time before the GPE starts. -GPE_BUFFER(GpeSetPstatesParms G_core_data_control_parms); +// create gpe request for GPE job. The initialization will be done one time +// during gpe request create. +GpeRequest G_core_data_control_req; -// Function Specification -// -// Name: proc_set_pstate -// -// Description: Function to demonstrate setting Pstates to all cores -// Should only be run from RTL -// -// End Function Specification -void proc_set_pstate_all(Pstate i_pstate) -{ - uint8_t l_chiplet = 0; +// Global double buffering for core data control +GPE_BUFFER(PstatesClips G_quads_data_control[2]) = {{{{0}}}}; - for(; l_chipletmsg_cb.rc == PGPE_RC_SUCCESS) ) // with no errors + { - set_chiplet_pmax(G_core_data_control_occwrite_ptr, - l_hw_core, - l_pmax); - set_chiplet_pmin(G_core_data_control_occwrite_ptr, - l_hw_core, - i_pmin); -} + //The previous OPAL PGPE request succeeded: + //1) swap gpewrite ptr with the occwrite ptr (double buffering). + l_temp = G_core_data_control_occwrite_ptr; + G_core_data_control_occwrite_ptr = G_core_data_control_gpewrite_ptr; + G_core_data_control_gpewrite_ptr = l_temp; -// Function Specification -// -// Name: proc_core_data_control_init -// -// Description: Initializations needed for core data control task -// -// End Function Specification -void proc_core_data_control_init( void ) -{ - errlHndl_t l_err = NULL; //Error handler - tracDesc_t l_trace = NULL; //Temporary trace descriptor - int rc = 0; //Return code + //2) Set clip values from gpewrite's quad clips data-structure + G_clip_update_parms_ptr = &G_core_data_control_gpewrite_ptr->clips; - do - { - //FIXME: Need to change this to use PGPE queue - //Initializes PoreFlex object for pstate control - rc = pore_flex_create( &G_core_data_control_req, //gpe_req for the task - &G_pore_gpe0_queue, //queue - gpe_set_pstates, //entry point - (uint32_t) &G_core_data_control_parms, //parm for the task - SSX_WAIT_FOREVER, //no timeout - NULL, //callback - NULL, //callback argument - 0 ); //options - if( rc ) + //call PGPE IPC function to update the clips + pgpe_clip_update(); + } + else if(G_clip_update_parms_ptr->msg_cb.rc != PGPE_RC_SUCCESS) { - //If fail to create pore flex object then there is a problem. - TRAC_ERR("Fail to create core control poreFlex object[0x%x]", rc ); + // an earlier clip update IPC call has not completed, trace and log an error + TRAC_ERR("task_core_data_control: clip update IPC task returned an error, %d", + G_clip_update_parms_ptr->msg_cb.rc); /* * @errortype - * @moduleid PROC_CORE_INIT_MOD - * @reasoncode SSX_GENERIC_FAILURE - * @userdata1 pore_flex_create return code - * @userdata4 ERC_PROC_CONTROL_INIT_FAILURE - * @devdesc Failure to create poreflex object + * @moduleid RTLS_TASK_CORE_DATA_CONTROL_MOD + * @reasoncode PGPE_FAILURE + * @userdata1 rc + * @userdata2 idle? + * @userdata4 ERC_PGPE_UNSUCCESSFULL + * @devdesc pgpe clip update returned an error */ - l_err = createErrl( - PROC_CORE_INIT_MOD, //modId - SSX_GENERIC_FAILURE, //reasoncode - ERC_PROC_CONTROL_INIT_FAILURE, //Extended reason code - ERRL_SEV_PREDICTIVE, //Severity - l_trace, //TODO: create l_trace //Trace Buf - DEFAULT_TRACE_SIZE, //Trace Size - rc, //userdata1 - 0 //userdata2 - ); - - // commit error log - REQUEST_RESET(l_err); //$gm006 - break; + err = createErrl( + RTLS_TASK_CORE_DATA_CONTROL_MOD, //ModId + PGPE_FAILURE, //Reasoncode + ERC_PGPE_UNSUCCESSFULL, //Extended reason code + ERRL_SEV_PREDICTIVE, //Severity + NULL, //Trace Buf + DEFAULT_TRACE_SIZE, //Trace Size + G_clip_update_parms_ptr->msg_cb.rc, //Userdata1 + async_request_is_idle(&G_clip_update_req.request) //Userdata2 + ); } - - } while(0); -} - -// Function Specification -// -// Name: task_core_data_control -// -// Description: Control core actuation for all configured cores on every tick. -// -// End Function Specification -void task_core_data_control( task_t * i_task ) -{ -//TEMP/TODO: proc_core_data_control_init needs to be called from proc_core_init() -// when this task is enabled for it to function properly. - errlHndl_t l_err = NULL; //Error handler - tracDesc_t l_trace = NULL; //Temporary trace descriptor - int rc = 0; //Return code - PcbsPstateRegs * l_temp = NULL; - - do + } + else { - - //Check to see if the previous GPE request still running - if( !(async_request_is_idle(&G_core_data_control_req.request)) ) + // NON OPAL System, OCC owns PMCR: + if( async_request_is_idle(&G_pmcr_set_req.request) && // PMCR IPC from last TICK completed + (G_pmcr_set_parms_ptr->msg_cb.rc == PGPE_RC_SUCCESS) ) // with no errors { - break; - } + //The previous Non-OPAL PGPE request succeeded: - //Check to see if the previosuly GPE request has been succeeded - if( async_request_completed(&G_core_data_control_req.request) ) - { - //If the previous GPE request succeeded then swap the - //gpewrite ptr with the occwrite ptr. + //1) swap gpewrite ptr with the occwrite ptr (double buffering). l_temp = G_core_data_control_occwrite_ptr; + G_core_data_control_occwrite_ptr = G_core_data_control_gpewrite_ptr; G_core_data_control_gpewrite_ptr = l_temp; - } - //Setup the core data control parms - G_core_data_control_parms.config = (uint64_t) (((uint64_t) G_present_hw_cores) << 32); - if(G_sysConfigData.system_type.kvm) - { - //Set the chiplet bounds (pmax/pmin) only on opal - G_core_data_control_parms.select = GPE_SET_PSTATES_PMBR; - } - else - { - //Set the chiplet pstate request on non-opal systems - G_core_data_control_parms.select = GPE_SET_PSTATES_PMCR; - } - - G_core_data_control_parms.regs = (uint32_t) G_core_data_control_gpewrite_ptr; + //2) Set Pstate values from gpewrite's quad pstates data-structure + G_pmcr_set_parms_ptr = &G_core_data_control_gpewrite_ptr->pstates; - rc = pore_flex_schedule( &G_core_data_control_req ); - if( rc != 0 ) + //call PGPE IPC function to update Pstates + pgpe_pmcr_set(); + } + else if(G_pmcr_set_parms_ptr->msg_cb.rc != PGPE_RC_SUCCESS) { - TRAC_ERR("Failed PoreFlex schedule core data control [%x] \n", rc); + // an earlier clip update IPC call has not completed, trace and log an error + TRAC_ERR("task_core_data_control: pstate update IPC task returned an error, %d", + G_pmcr_set_parms_ptr->msg_cb.rc); /* * @errortype - * @moduleid PROC_TASK_CORE_DATA_MOD - * @reasoncode SSX_GENERIC_FAILURE - * @userdata1 pore_flex_schedule return code - * @userdata4 ERC_PROC_CONTROL_TASK_FAILURE - * @devdesc Failure to schedule poreflex object + * @moduleid RTLS_TASK_CORE_DATA_CONTROL_MOD + * @reasoncode PGPE_FAILURE + * @userdata1 rc + * @userdata4 ERC_PGPE_UNSUCCESSFULL + * @devdesc pgpe PMCR set returned an error */ - l_err = createErrl( - PROC_TASK_CORE_DATA_MOD, //modId - SSX_GENERIC_FAILURE, //reasoncode - ERC_PROC_CONTROL_TASK_FAILURE, //Extended reason code - ERRL_SEV_PREDICTIVE, //Severity - l_trace, //TODO: create l_trace //Trace Buf - DEFAULT_TRACE_SIZE, //Trace Size - rc, //userdata1 - 0 //userdata2 - ); - - // commit error log - REQUEST_RESET(l_err); - break; + err = createErrl( + RTLS_TASK_CORE_DATA_CONTROL_MOD, //ModId + PGPE_FAILURE, //Reasoncode + ERC_PGPE_UNSUCCESSFULL, //Extended reason code + ERRL_SEV_PREDICTIVE, //Severity + NULL, //Trace Buf + DEFAULT_TRACE_SIZE, //Trace Size + G_pmcr_set_parms_ptr->msg_cb.rc, //Userdata1 + 0 //Userdata2 + ); } - } while(0); + } + + if(err) + { + // commit error log + REQUEST_RESET(err); + } return; } diff --git a/src/occ_405/proc/proc_data_control.h b/src/occ_405/proc/proc_data_control.h index ec65c2f7..4188c08b 100755 --- a/src/occ_405/proc/proc_data_control.h +++ b/src/occ_405/proc/proc_data_control.h @@ -30,21 +30,26 @@ #include #include "rtls.h" #include "p9_pstates_common.h" +#include "pstate_pgpe_occ_api.h" -//#include "gpe_control.h" +/// Per-quad Pstate/Clip control data-structure +/// +/// Firmware maintains a copy of PstateClipStruct structures - with an entry +/// for each quad on the chip - and updates the pstate/clip fields in place. +/// The PGPE IPC procedures (MSGID_405_SET_PMCR and MSGID_405_CLIPS) +/// are run periodically to update the core psates or clips control values +/// from this data structure. The array can (should) be cleared initially. +typedef struct { -// Initialze the structures used by the GPE -void proc_core_data_control_init( void ); + /// The Pstate control values + ipcmsg_set_pmcr_t pstates; -// Task that sets the PMCR, PMBR, PMICR -void task_core_data_control( task_t * i_task ); + /// The clipping values + ipcmsg_clip_update_t clips; -// Function to demonstrate setting Pstates to all cores -void proc_set_pstate_all(Pstate i_pstate); +} PstatesClips; -// Function to demonstrate setting Pstates one core -void proc_set_core_pstate(Pstate i_pstate, uint8_t i_core); +// Task that sets the PMCR, PMBR, PMICR +void task_core_data_control( task_t * i_task ); -// Sets the Pmin/Pmax clip values for one core -void proc_set_core_bounds(Pstate i_pmin, Pstate i_pmax, uint8_t i_core); #endif diff --git a/src/occ_405/proc/proc_pstate.c b/src/occ_405/proc/proc_pstate.c index d63c96fa..15b66d8b 100755 --- a/src/occ_405/proc/proc_pstate.c +++ b/src/occ_405/proc/proc_pstate.c @@ -40,30 +40,28 @@ #include #include #include +#include +#include //OPAL processor and memory throttle reason coming from the frequency voting boxes. extern opal_proc_voting_reason_t G_amec_opal_proc_throt_reason; extern opal_mem_voting_reason_t G_amec_opal_mem_throt_reason; -// Holds Fmax for ease of proc_freq2pstate calculation -uint32_t G_proc_fmax = 0; +//Global OCC Pstate Parameters Block Structure +extern OCCPstateParmBlock G_oppb; -// Holds Fmin for ease of proc_freq2pstate calculation -uint32_t G_proc_fmin = 0; +//Holds Fmax for ease of proc_freq2pstate calculation = max(fturbo,futurbo) +uint16_t G_proc_fmax_mhz; -// Holds frequency steps between consequtive Pstates -uint32_t G_khz_per_pstate = 0; +// A global variable indicating whether the pstates have been enabled. +// initialized to PSTATES_DISABLED, turns to PSTATES_ENABLED only after +// the PGPE IPC that enable pstates completes successfully. While the IPC +// task is still running, this variable be set to PSTATES_IN_TRANSITION +pstateStatus G_proc_pstate_status = PSTATES_DISABLED; -// Holds Pmax for ease of proc_freq2pstate calculation -uint8_t G_proc_pmax = 0; -// Holds Pmin for ease of proc_freq2pstate calculation -uint8_t G_proc_pmin = 0; - -// Holds a flag indicating whether the pstates have been enabled. -// initialized to FALSE, turns TRUE only after the PGPE IPC that -// enable pstates completes successfully. -bool G_proc_pstate_enabled = FALSE; +// A Global parameter indicating the owner of the PMCR. +PMCR_OWNER G_proc_pmcr_owner = G_sysConfigData.system_type.kvm? PMCR_OWNER_HOST: PMCR_OWNER_HOST; // OPAL Dynamic data, updated whenever any OCC G_opal_table.dynamic parameter change DMA_BUFFER( opal_dynamic_table_t G_opal_dynamic_table ) = {{0}}; @@ -81,7 +79,7 @@ DMA_BUFFER( opal_static_table_t G_opal_static_table ) = {{0}}; // End Function Specification bool proc_is_hwpstate_enabled(void) { - return ( G_proc_pstate_enabled ? TRUE : FALSE); + return ( G_proc_pstate_status == PSTATES_ENABLED ? TRUE : FALSE); } // Function Specification @@ -93,20 +91,16 @@ bool proc_is_hwpstate_enabled(void) // End Function Specification uint32_t proc_pstate2freq(Pstate i_pstate) { - // If passed in Pstate is lower than Pmin, just use Pmin - if(i_pstate < G_proc_pmin) - { - i_pstate = G_proc_pmin; - } - - // If passed in Pstate is greater than Pmax, just use Pmax - else if (i_pstate > G_proc_pmax) + // The higher the pstate number, the lower the frequency: + // If passed in Pstate is lower than Pmin (higher pstate value), + // just use Pmin. + if(i_pstate > G_oppb.pstate_min) { - i_pstate = G_proc_pmax; + i_pstate = G_oppb.pstate_min; } // Calculate Frequency in kHz based on Pstate - return (G_proc_fmin + (G_proc_pmin - i_pstate) * G_khz_per_pstate); + return ( G_oppb.frequency_max_khz - (i_pstate * G_oppb.frequency_step_khz)); } // Function Specification @@ -135,29 +129,21 @@ Pstate proc_freq2pstate(uint32_t i_freq_mhz) l_freq_khz = G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY] * 1000; } - if(l_freq_khz < G_proc_fmax) + if(l_freq_khz < G_proc_fmax_mhz * 1000) { // First, calculate the delta between passed in freq, and Pmin - l_temp_freq = l_freq_khz - G_proc_fmin; - - // Check if the passed in frequency is lower than Minimum Frequency - if(l_freq_khz <= G_proc_fmin) - { - // We need to substract a full step (minus 1) to make sure we - // are keeping things safe - l_temp_freq -= (G_khz_per_pstate - 1); - } + l_temp_freq = l_freq_khz - G_oppb.frequency_min_khz; // Next, calculate how many Pstate steps there are in that delta - l_temp_pstate = l_temp_freq / (int32_t) G_khz_per_pstate; + l_temp_pstate = l_temp_freq / (int32_t) G_oppb.frequency_step_khz; // Lastly, calculate Pstate, by adding delta Pstate steps to Pmin - l_pstate = G_proc_pmin - l_temp_pstate; + l_pstate = G_oppb.pstate_min - l_temp_pstate; } else { // Freq is higher than maximum frequency -- return Pmax - l_pstate = G_proc_pmax; + l_pstate = PMAX + (G_oppb.frequency_max_khz - G_proc_fmax_mhz*1000)/G_oppb.frequency_step_khz; } } while(0); @@ -183,11 +169,13 @@ void proc_pstate_kvm_setup() break; } + TRAC_INFO("proc_pstate_kvm_setup: populate static OPAL data"); + // Initialize the opal table in SRAM (sets valid bit) - populate_static_opal_data(); + populate_opal_static_data(); // copy sram image into mainstore HOMER - populate_opal_tbl_to_mem(); + populate_opal_tbl_to_mem(OPAL_STATIC); TRAC_IMP("proc_pstate_kvm_setup: RUNNING IN KVM MODE"); }while(0); @@ -195,12 +183,12 @@ void proc_pstate_kvm_setup() // Function Specification // -// Name: populate_dynamic_opal_data +// Name: populate_opal_dynamic_data // // Description: populate the dynamic data entries in the OPAL table // // End Function Specification -void populate_dynamic_opal_data() +void populate_opal_dynamic_data() { memset(&G_opal_dynamic_table, 0, sizeof(G_opal_dynamic_table)); @@ -228,18 +216,33 @@ void populate_dynamic_opal_data() // Function Specification // -// Name: populate_static_opal_data +// Name: populate_opal_static_data // // Description: populate the static configuration entries, // the generated pstates table, and maximum pstates // for all possible number of active cores. // // End Function Specification -void populate_static_opal_data() +void populate_opal_static_data() { - memset(&G_opal_dynamic_table, 0, sizeof(G_opal_dynamic_table)); + // clear all entries of the OPAL static table + memset(&G_opal_static_table, 0, sizeof(G_opal_static_table)); + + populate_opal_static_config_data(); + populate_opal_static_pstates_data(); +} + +// Function Specification +// +// Name: populate_opal_static_config_data +// +// Description: populate the static configuration entries, +// +// End Function Specification +void populate_opal_static_config_data(void) +{ // Static OPAL configuration data G_opal_static_table.config.valid = 1; G_opal_static_table.config.version = 0x90; @@ -247,43 +250,90 @@ void populate_static_opal_data() G_opal_static_table.config.pmin = pmin_rail(); G_opal_static_table.config.pnominal = proc_freq2pstate(G_sysConfigData.sys_mode_freq.table[OCC_MODE_NOMINAL]); G_opal_static_table.config.pturbo = proc_freq2pstate(G_sysConfigData.sys_mode_freq.table[OCC_MODE_TURBO]); - G_opal_static_table.config.puturbo = proc_freq2pstate(G_sysConfigData.sys_mode_freq.table[OCC_MODE_UTURBO]); + G_opal_static_table.config.puturbo = proc_freq2pstate(G_proc_fmax_mhz); +} + +// Function Specification +// +// Name: populate_opal_static_data +// +// Description: populate the generated pstates table, and maximum +// pstates for all possible number of active cores. +// +// End Function Specification +void populate_opal_static_pstates_data(void) +{ + uint16_t i; // loop variable + for (i=0; i <= G_oppb.pstate_min; i++) + { + G_opal_static_table.pstates[i].pstate = i; // pstate number + G_opal_static_table.pstates[i].flag = 0; // flag is reserved for future use + G_opal_static_table.pstates[i].freq_khz = proc_pstate2freq(i); // pstate's frequency + } - // TODO - RTC:130201 generate pstates table & Max pstates for var #cores + for (i=0; i move to initialization code, reading from parameter block - G_proc_fmax = 4322500; - G_proc_fmin = 2028250; - G_khz_per_pstate = 33250; - G_proc_pmax = 0; - G_proc_pmin = G_proc_pmax + ((G_proc_fmax - G_proc_fmin)/G_khz_per_pstate); - - // Set globals used by amec for pcap calculation - // could have used G_khz_per_pstate in PCAP calculations - // instead, but using a separate varaible speeds up PCAP related - // calculations significantly, by eliminating division operations. - G_mhz_per_pstate = G_khz_per_pstate/1000; - - TRAC_INFO("proc_pstate_initialize: Pstate Key globals initialized to default values"); - -} // Function Specification // @@ -429,14 +441,14 @@ void check_for_opal_updates(void) // End Function Specification void update_dynamic_opal_data (void) { + TRAC_INFO("update_dynamic_opal_data: populate dynamic OPAL data"); + // Initialize the opal table in SRAM (sets valid bit) - populate_dynamic_opal_data(); + populate_opal_dynamic_data(); // copy sram image into mainstore HOMER - populate_opal_tbl_to_mem(); - TRAC_IMP("update_dynamic_opal_data: update dynamic OPAL data"); - - + populate_opal_tbl_to_mem(OPAL_DYNAMIC); + TRAC_IMP("update_dynamic_opal_data: updated dynamic OPAL data"); } @@ -451,14 +463,15 @@ void update_dynamic_opal_data (void) // End Function Specification uint8_t pmin_rail(void) { - uint8_t configMinPstate = proc_freq2pstate(G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY]); + uint8_t configMinPstate = + proc_freq2pstate(G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY]); - if(configMinPstate < G_proc_pmin) + if(configMinPstate < G_oppb.pstate_min) { return configMinPstate; } else { - return G_proc_pmin; + return G_oppb.pstate_min; } } diff --git a/src/occ_405/proc/proc_pstate.h b/src/occ_405/proc/proc_pstate.h index 962c71a1..b552237a 100755 --- a/src/occ_405/proc/proc_pstate.h +++ b/src/occ_405/proc/proc_pstate.h @@ -39,6 +39,25 @@ //#include "gpsm.h" //#include "pstates.h" +// The pstate associated with highest possible frequency +// is always 0 in POWER9. +#define PMAX 0 + +typedef enum +{ + PSTATES_IN_TRANSITION = -1, + PSTATES_DISABLED = 0, + PSTATES_ENABLED = 1, +} pstateStatus; + + +typedef enum +{ + OPAL_STATIC = 0, + OPAL_DYNAMIC = 1, +} opalDataType; + + typedef struct __attribute__ ((packed)) { uint8_t valid; @@ -100,9 +119,7 @@ typedef struct __attribute__ ((packed)) extern uint32_t G_mhz_per_pstate; extern opal_dynamic_table_t G_opal_dynamic_table; - -// Initialize PState Key parameters -void proc_pstate_initialize(void); +extern opal_static_table_t G_opal_static_table; // Helper function to translate from Frequency to nearest Pstate Pstate proc_freq2pstate(uint32_t i_freq_mhz); @@ -115,13 +132,19 @@ Pstate proc_freq2pstate(uint32_t i_freq_mhz); inline bool proc_is_hwpstate_enabled(void); // Copy pstate data to opal table -void populate_dynamic_opal_data(void); +void populate_opal_dynamic_data(void); // Copy all opal static data to opal table -void populate_static_opal_data(void); +void populate_opal_static_data(void); + +// Copy pstates sections of opal static data to opal table +void populate_opal_static_pstates_data(void); + +// Copy config section of opal static data to opal table +void populate_opal_static_config_data(void); -// Copy opal table to mainstore memory at OPAL_OFFSET_HOMER -void populate_opal_tbl_to_mem(void); +// Copy opal static/dynamic table to mainstore memory at OPAL_OFFSET_HOMER +void populate_opal_tbl_to_mem(opalDataType opal_data_type); // Check if opal table needs update void check_for_opal_updates(void); diff --git a/src/occ_405/pss/apss.c b/src/occ_405/pss/apss.c index e93b156a..ae4d100d 100755 --- a/src/occ_405/pss/apss.c +++ b/src/occ_405/pss/apss.c @@ -1097,7 +1097,7 @@ errlHndl_t initialize_apss(void) //Create the request for measure start. Scheduling will happen in apss.c gpe_request_create(&G_meas_start_request, &G_async_gpe_queue0, // queue - IPC_ST_APSS_START_PWR_MEAS_READ_FUNCID, // entry_point + IPC_ST_APSS_START_PWR_MEAS_READ_FUNCID, // entry_point &G_gpe_start_pwr_meas_read_args, // entry_point arg SSX_WAIT_FOREVER, // no timeout NULL, // callback diff --git a/src/occ_405/rtls/rtls.h b/src/occ_405/rtls/rtls.h index 6da68254..8babaab2 100755 --- a/src/occ_405/rtls/rtls.h +++ b/src/occ_405/rtls/rtls.h @@ -53,11 +53,11 @@ typedef enum { TASK_ID_DCOM_TX_OUTBX, TASK_ID_MISC_405_CHECKS, // Miscellaneous checks to be done by 405 TASK_ID_DCOM_PARSE_FW_MSG, - TASK_ID_AMEC_SLAVE, // AMEC SMH tasks - TASK_ID_AMEC_MASTER, // AMEC SMH tasks -// TASK_ID_CORE_DATA_CONTROL, // TODO RTC: 163365 + TASK_ID_AMEC_SLAVE, // AMEC SMH tasks + TASK_ID_AMEC_MASTER, // AMEC SMH tasks + TASK_ID_CORE_DATA_CONTROL, // TASK_ID_GPU_SM, // GPU State Machine TODO RTC: 133824 - TASK_ID_DIMM_SM, // DIMM State Machine + TASK_ID_DIMM_SM, // DIMM State Machine TASK_ID_MEMORY_CONTROL, // Memory (centaur/dimm) control task TASK_ID_NEST_DTS, TASK_END // This must always be the last enum in this list, diff --git a/src/occ_405/rtls/rtls_service_codes.h b/src/occ_405/rtls/rtls_service_codes.h index 5aab7280..44f20d84 100755 --- a/src/occ_405/rtls/rtls_service_codes.h +++ b/src/occ_405/rtls/rtls_service_codes.h @@ -30,12 +30,13 @@ enum rtlsModuleId { - RTLS_OCB_INIT_MOD = RTLS_COMP_ID | 0x00, - RTLS_DO_TICK_MOD = RTLS_COMP_ID | 0x01, - RTLS_START_TASK_MOD = RTLS_COMP_ID | 0x02, - RTLS_STOP_TASK_MOD = RTLS_COMP_ID | 0x03, - RTLS_TASK_RUNABLE_MOD = RTLS_COMP_ID | 0x04, - RTLS_SET_TASK_DATA_MOD = RTLS_COMP_ID | 0x05, + RTLS_OCB_INIT_MOD = RTLS_COMP_ID | 0x00, + RTLS_DO_TICK_MOD = RTLS_COMP_ID | 0x01, + RTLS_START_TASK_MOD = RTLS_COMP_ID | 0x02, + RTLS_STOP_TASK_MOD = RTLS_COMP_ID | 0x03, + RTLS_TASK_RUNABLE_MOD = RTLS_COMP_ID | 0x04, + RTLS_SET_TASK_DATA_MOD = RTLS_COMP_ID | 0x05, + RTLS_TASK_CORE_DATA_CONTROL_MOD = RTLS_COMP_ID | 0x06, }; #endif /* #ifndef _RTLS_SERVICE_CODES_H_ */ diff --git a/src/occ_405/rtls/rtls_tables.c b/src/occ_405/rtls/rtls_tables.c index b7b1a4cb..fdcce40a 100755 --- a/src/occ_405/rtls/rtls_tables.c +++ b/src/occ_405/rtls/rtls_tables.c @@ -113,8 +113,7 @@ task_t G_task_table[TASK_END] = { { FLAGS_DCOM_PARSE_OCC_FW_MSG, task_dcom_parse_occfwmsg, NULL }, // TASK_ID_DCOM_PARSE_FW_MSG { FLAGS_AMEC_SLAVE, task_amec_slave, NULL }, // TASK_ID_AMEC_SLAVE { FLAGS_AMEC_MASTER, task_amec_master, NULL }, // TASK_ID_AMEC_MASTER -// TODO RTC: 163365 - /proc/ and /pss/ "TODO" cleanup -// { FLAGS_CORE_DATA_CONTROL, task_core_data_control, NULL }, // TASK_ID_CORE_DATA_CONTROL + { FLAGS_CORE_DATA_CONTROL, task_core_data_control, NULL }, // TASK_ID_CORE_DATA_CONTROL // TODO RTC: 133824 - New GPU interface via main memory and SMBUS // { FLAGS_GPU_SM, task_gpu_sm, NULL }, // TASK_ID_GPU_SM { FLAGS_MEMORY_DATA, task_dimm_sm, NULL }, // TASK_ID_DIMM_SM @@ -130,7 +129,7 @@ const uint8_t G_tick0_seq[] = { TASK_ID_CORE_DATA_HIGH, TASK_ID_APSS_DONE, TASK_ID_MEMORY_CONTROL, - //TASK_ID_CORE_DATA_CONTROL, + TASK_ID_CORE_DATA_CONTROL, TASK_ID_DCOM_WAIT_4_MSTR, TASK_ID_DCOM_RX_INBX, TASK_ID_DCOM_RX_OUTBX, @@ -149,7 +148,7 @@ const uint8_t G_tick1_seq[] = { TASK_ID_APSS_CONT, TASK_ID_APSS_DONE, TASK_ID_MEMORY_CONTROL, - //TASK_ID_CORE_DATA_CONTROL, + TASK_ID_CORE_DATA_CONTROL, TASK_ID_DCOM_WAIT_4_MSTR, TASK_ID_DCOM_RX_INBX, TASK_ID_DCOM_RX_OUTBX, @@ -170,7 +169,7 @@ const uint8_t G_tick2_seq[] = { TASK_ID_CORE_DATA_HIGH, TASK_ID_APSS_DONE, TASK_ID_MEMORY_CONTROL, - //TASK_ID_CORE_DATA_CONTROL, + TASK_ID_CORE_DATA_CONTROL, TASK_ID_DCOM_WAIT_4_MSTR, TASK_ID_DCOM_RX_INBX, TASK_ID_DCOM_RX_OUTBX, @@ -190,7 +189,7 @@ const uint8_t G_tick3_seq[] = { TASK_ID_CORE_DATA_HIGH, TASK_ID_APSS_DONE, TASK_ID_MEMORY_CONTROL, - //TASK_ID_CORE_DATA_CONTROL, + TASK_ID_CORE_DATA_CONTROL, TASK_ID_DCOM_WAIT_4_MSTR, TASK_ID_DCOM_RX_INBX, TASK_ID_DCOM_RX_OUTBX, @@ -210,7 +209,7 @@ const uint8_t G_tick4_seq[] = { TASK_ID_CORE_DATA_HIGH, TASK_ID_APSS_DONE, TASK_ID_MEMORY_CONTROL, - //TASK_ID_CORE_DATA_CONTROL, + TASK_ID_CORE_DATA_CONTROL, TASK_ID_DCOM_WAIT_4_MSTR, TASK_ID_DCOM_RX_INBX, TASK_ID_DCOM_RX_OUTBX, @@ -229,7 +228,7 @@ const uint8_t G_tick5_seq[] = { TASK_ID_APSS_CONT, TASK_ID_APSS_DONE, TASK_ID_MEMORY_CONTROL, - //TASK_ID_CORE_DATA_CONTROL, + TASK_ID_CORE_DATA_CONTROL, TASK_ID_DCOM_WAIT_4_MSTR, TASK_ID_DCOM_RX_INBX, TASK_ID_DCOM_RX_OUTBX, @@ -249,7 +248,7 @@ const uint8_t G_tick6_seq[] = { TASK_ID_CORE_DATA_HIGH, TASK_ID_APSS_DONE, TASK_ID_MEMORY_CONTROL, - //TASK_ID_CORE_DATA_CONTROL, + TASK_ID_CORE_DATA_CONTROL, TASK_ID_DCOM_WAIT_4_MSTR, TASK_ID_DCOM_RX_INBX, TASK_ID_DCOM_RX_OUTBX, @@ -268,7 +267,7 @@ const uint8_t G_tick7_seq[] = { TASK_ID_CORE_DATA_HIGH, TASK_ID_APSS_DONE, TASK_ID_MEMORY_CONTROL, - //TASK_ID_CORE_DATA_CONTROL, + TASK_ID_CORE_DATA_CONTROL, TASK_ID_DCOM_WAIT_4_MSTR, TASK_ID_DCOM_RX_INBX, TASK_ID_DCOM_RX_OUTBX, @@ -288,7 +287,7 @@ const uint8_t G_tick8_seq[] = { TASK_ID_CORE_DATA_HIGH, TASK_ID_APSS_DONE, TASK_ID_MEMORY_CONTROL, - //TASK_ID_CORE_DATA_CONTROL, + TASK_ID_CORE_DATA_CONTROL, TASK_ID_DCOM_WAIT_4_MSTR, TASK_ID_DCOM_RX_INBX, TASK_ID_DCOM_RX_OUTBX, @@ -307,7 +306,7 @@ const uint8_t G_tick9_seq[] = { TASK_ID_APSS_CONT, TASK_ID_APSS_DONE, TASK_ID_MEMORY_CONTROL, - //TASK_ID_CORE_DATA_CONTROL, + TASK_ID_CORE_DATA_CONTROL, TASK_ID_DCOM_WAIT_4_MSTR, TASK_ID_DCOM_RX_INBX, TASK_ID_DCOM_RX_OUTBX, @@ -328,7 +327,7 @@ const uint8_t G_tick10_seq[] = { TASK_ID_CORE_DATA_HIGH, TASK_ID_APSS_DONE, TASK_ID_MEMORY_CONTROL, - //TASK_ID_CORE_DATA_CONTROL, + TASK_ID_CORE_DATA_CONTROL, TASK_ID_DCOM_WAIT_4_MSTR, TASK_ID_DCOM_RX_INBX, TASK_ID_DCOM_RX_OUTBX, @@ -347,7 +346,7 @@ const uint8_t G_tick11_seq[] = { TASK_ID_CORE_DATA_HIGH, TASK_ID_APSS_DONE, TASK_ID_MEMORY_CONTROL, - //TASK_ID_CORE_DATA_CONTROL, + TASK_ID_CORE_DATA_CONTROL, TASK_ID_DCOM_WAIT_4_MSTR, TASK_ID_DCOM_RX_INBX, TASK_ID_DCOM_RX_OUTBX, @@ -367,7 +366,7 @@ const uint8_t G_tick12_seq[] = { TASK_ID_CORE_DATA_HIGH, TASK_ID_APSS_DONE, TASK_ID_MEMORY_CONTROL, - //TASK_ID_CORE_DATA_CONTROL, + TASK_ID_CORE_DATA_CONTROL, TASK_ID_DCOM_WAIT_4_MSTR, TASK_ID_DCOM_RX_INBX, TASK_ID_DCOM_RX_OUTBX, @@ -386,7 +385,7 @@ const uint8_t G_tick13_seq[] = { TASK_ID_APSS_CONT, TASK_ID_APSS_DONE, TASK_ID_MEMORY_CONTROL, - //TASK_ID_CORE_DATA_CONTROL, + TASK_ID_CORE_DATA_CONTROL, TASK_ID_DCOM_WAIT_4_MSTR, TASK_ID_DCOM_RX_INBX, TASK_ID_DCOM_RX_OUTBX, @@ -406,7 +405,7 @@ const uint8_t G_tick14_seq[] = { TASK_ID_CORE_DATA_HIGH, TASK_ID_APSS_DONE, TASK_ID_MEMORY_CONTROL, - //TASK_ID_CORE_DATA_CONTROL, + TASK_ID_CORE_DATA_CONTROL, TASK_ID_DCOM_WAIT_4_MSTR, TASK_ID_DCOM_RX_INBX, TASK_ID_DCOM_RX_OUTBX, @@ -425,7 +424,7 @@ const uint8_t G_tick15_seq[] = { TASK_ID_CORE_DATA_HIGH, TASK_ID_APSS_DONE, TASK_ID_MEMORY_CONTROL, - //TASK_ID_CORE_DATA_CONTROL, + TASK_ID_CORE_DATA_CONTROL, TASK_ID_DCOM_WAIT_4_MSTR, TASK_ID_DCOM_RX_INBX, TASK_ID_DCOM_RX_OUTBX, diff --git a/src/occ_405/state.c b/src/occ_405/state.c index 956d06e3..bac2de89 100755 --- a/src/occ_405/state.c +++ b/src/occ_405/state.c @@ -32,18 +32,23 @@ #include "state.h" #include "dcom.h" #include "occ_service_codes.h" -#include "proc_pstate.h" #include "cmdh_fsp_cmds_datacnfg.h" #include "cmdh_fsp.h" #include "proc_data.h" #include "scom.h" #include #include +#include "pgpe_interface.h" +#include "pstate_pgpe_occ_api.h" extern bool G_mem_monitoring_allowed; extern task_t G_task_table[TASK_END]; // Global task table extern bool G_simics_environment; +extern GpeRequest G_clip_update_req; +extern GPE_BUFFER(ipcmsg_clip_update_t* G_clip_update_parms_ptr); + + // Maximum allowed value approx. 16.3 ms #define PCBS_HEARBEAT_TIME_US 16320 @@ -141,9 +146,6 @@ errlHndl_t SMGR_standby_to_observation() rtl_clr_run_mask_deferred(RTL_FLAG_STANDBY); rtl_set_run_mask_deferred(RTL_FLAG_OBS); - // Initialize key freq2pstate Global parameters - proc_pstate_initialize(); - // Set the actual STATE now that we have finished everything else CURRENT_STATE() = OCC_STATE_OBSERVATION; @@ -211,9 +213,9 @@ errlHndl_t SMGR_observation_to_standby() // Function Specification // -// Name: +// Name: SMGR_observation_to_active // -// Description: +// Description: Transition from Observation state to Active state // // End Function Specification errlHndl_t SMGR_observation_to_active() @@ -223,19 +225,89 @@ errlHndl_t SMGR_observation_to_active() int l_extRc = OCC_NO_EXTENDED_RC; int l_rc = 0; - // Pstates are enabled via an IPC call to PGPE once the OCC reaches the - // observation state. We still have to check that the enable_pstates() IPC job - // on the PGPE has completed before transitioning to active state. Otherwise, - // we wait TBD seconds in case we are going directly from Standby to Active - // (pstate init only happens in observation state, so it might not be - // done yet...must call it in this while loop since it is done in this - // same thread...) - // + // confirm that the clip update IPC call to widen clip ranges + // has successfully completed on PGPE (with no errors) + if( !async_request_is_idle(&G_clip_update_req.request) ) //widen_clip_ranges didn't complete + { + // an earlier clip update IPC call has not completed, trace and log an error + TRAC_ERR("SMGR: clip update IPC task is not Idle"); + + /* + * @errortype + * @moduleid MAIN_SMGR_MID + * @reasoncode PGPE_FAILURE + * @userdata4 ERC_PGPE_NOT_IDLE + * @devdesc pgpe clip update not idle + */ + l_errlHndl = createErrl( + MAIN_SMGR_MID, //ModId + PGPE_FAILURE, //Reasoncode + ERC_PGPE_NOT_IDLE, //Extended reason code + ERRL_SEV_PREDICTIVE, //Severity + NULL, //Trace Buf + DEFAULT_TRACE_SIZE, //Trace Size + 0, //Userdata1 + 0 //Userdata2 + ); + // TODO now: REQUEST_RESET? + } + else if ( G_clip_update_parms_ptr->msg_cb.rc != PGPE_RC_SUCCESS ) // IPC task completed with errors + { + // an earlier clip update IPC call has not completed, trace and log an error + TRAC_ERR("SMGR: clip update IPC task returned an error [0x%08X]", + G_clip_update_parms_ptr->msg_cb.rc); + + /* + * @errortype + * @moduleid MAIN_SMGR_MID + * @reasoncode PGPE_FAILURE + * @userdata1 PGPE clip update's rc + * @userdata4 ERC_PGPE_CLIP_FAILURE + * @devdesc pgpe clip update not idle + */ + l_errlHndl = createErrl( + MAIN_SMGR_MID, //ModId + PGPE_FAILURE, //Reasoncode + ERC_PGPE_CLIP_FAILURE, //Extended reason code + ERRL_SEV_PREDICTIVE, //Severity + NULL, //Trace Buf + DEFAULT_TRACE_SIZE, //Trace Size + G_clip_update_parms_ptr->msg_cb.rc, //Userdata1 + 0 //Userdata2 + ); + // TODO now: REQUEST_RESET? + } + + else // Clips wide opened with no errors, enable Pstates on PGPE + { + + // Pstates are enabled via an IPC call to PGPE, which will + // set the G_proc_pstate_status flag + + l_errlHndl = pgpe_start_suspend(PGPE_ACTION_PSTATE_START); + + if(l_errlHndl) + { + TRAC_ERR("SMGR: Failed to switch to Active state because of a " + "failure to start the pstate protocol on PGPE."); + } + else + { + // Pstates enabled, update OPAL static table in main memory + if(G_sysConfigData.system_type.kvm) + { + // upon succesful enablement of Pstate protocol on + // PGPE update OPAL table with pstate information. + proc_pstate_kvm_setup(); + } + } + } + // NOTE that this is really unnecessary if you follow the TMGT OCC // Interface Spec, which tells you that you need to check for the "Active // Ready" bit in the poll response before you go to active state. // But since we have scenerios where TMGT isn't the one putting us in - // active state (we are going there automatically) we needed to add this + // active state (we are going there automatically) we needed to add this. // If we have all data we need to go to active state, but don't have pstates // enabled yet...then we will do the aforementioned wait @@ -253,8 +325,8 @@ errlHndl_t SMGR_observation_to_active() { TRAC_ERR("SMGR: Timeout waiting for Pstates to be enabled, " "pmc_mode[%08x], chips_present[%02x], Cores Present [%08x]", - in32(PMC_MODE_REG), - G_sysConfigData.is_occ_present, + in32(PMC_MODE_REG), + G_sysConfigData.is_occ_present, (uint32_t) ((in64(OCB_CCSR)) >> 32)); } l_extRc = ERC_GENERIC_TIMEOUT; diff --git a/src/occ_405/timer/timer.c b/src/occ_405/timer/timer.c index ef42c5c0..78934972 100755 --- a/src/occ_405/timer/timer.c +++ b/src/occ_405/timer/timer.c @@ -507,15 +507,15 @@ void check_pgpe_beacon(void) /* * @errortype * @moduleid POKE_WD_TIMERS - * @reasoncode INTERNAL_HW_FAILURE + * @reasoncode PGPE_FAILURE * @userdata1 PGPE Beacon Value * @userdata2 PGPE Beacon Address - * @userdata4 PGPE_BEACON_TIMEOUT + * @userdata4 ERC_PGPE_BEACON_TIMEOUT * @devdesc PGPE Beacon timeout */ l_err = createErrl(POKE_WD_TIMERS, // mod id - PGPE_BEACON_TIMEOUT, // reason code - OCC_NO_EXTENDED_RC, // Extended reason code + PGPE_FAILURE, // reason code + ERC_PGPE_BEACON_TIMEOUT, // Extended reason code ERRL_SEV_UNRECOVERABLE, // severity NULL, // trace buffer 0, // trace size diff --git a/src/occ_405/topfiles.mk b/src/occ_405/topfiles.mk index c5c16a07..ed33ebf9 100644 --- a/src/occ_405/topfiles.mk +++ b/src/occ_405/topfiles.mk @@ -72,7 +72,9 @@ TOP-C-SOURCES = amec/amec_analytics.c \ mode.c \ occ_sys_config.c \ occbuildname.c \ + pgpe/pgpe_interface.c \ proc/proc_data.c \ + proc/proc_data_control.c \ proc/proc_pstate.c \ pss/apss.c \ pss/avsbus.c \